Commit a28a90ec authored by Him188's avatar Him188

Group member permission determination and change

parent e3c3c712
...@@ -27,10 +27,11 @@ Mirai 在 JVM 平台采用插件模式运行,同时提供独立的跨平台核 ...@@ -27,10 +27,11 @@ Mirai 在 JVM 平台采用插件模式运行,同时提供独立的跨平台核
- 接受解析好友消息(10/14) - 接受解析好友消息(10/14)
- 接收解析群消息(10/14) - 接收解析群消息(10/14)
- 成员昵称(10/18) - 成员昵称(10/18)
- 成员权限(10/18, 计划优化) - 成员权限(11/2)
- 好友在线状态改变(10/14) - 好友在线状态改变(10/14)
- Android客户端上线/下线(10/18) - Android客户端上线/下线(10/18)
- 上传并发送好友/群图片(10/21, 10/26) - 上传并发送好友/群图片(10/21, 10/26)
- 群员权限改变(11/2)
计划中: 添加好友 计划中: 添加好友
......
...@@ -18,7 +18,7 @@ import kotlin.jvm.JvmName ...@@ -18,7 +18,7 @@ import kotlin.jvm.JvmName
/** /**
* 消息事件时创建的临时容器. * 消息事件时创建的临时容器.
*/ */
abstract class SenderAndMessage<S : Contact>( abstract class SenderAndMessage<TContact : Contact>(
/** /**
* 发送这条消息的用户. * 发送这条消息的用户.
*/ */
...@@ -26,7 +26,7 @@ abstract class SenderAndMessage<S : Contact>( ...@@ -26,7 +26,7 @@ abstract class SenderAndMessage<S : Contact>(
/** /**
* 消息事件主体. 对于好友消息, 这个属性为 [QQ] 的实例; 对于群消息, 这个属性为 [Group] 的实例 * 消息事件主体. 对于好友消息, 这个属性为 [QQ] 的实例; 对于群消息, 这个属性为 [Group] 的实例
*/ */
val subject: S, val subject: TContact,
val message: MessageChain val message: MessageChain
) { ) {
/** /**
......
...@@ -59,9 +59,18 @@ fun main() { ...@@ -59,9 +59,18 @@ fun main() {
internal fun IoBuffer.parseMessageImage0x03(): Image { internal fun IoBuffer.parseMessageImage0x03(): Image {
discardExact(1) discardExact(1)
return Image(ImageId(String(readLVByteArray())))
return Image(ImageId(String(readLVByteArray()).adjustImageId()))
} }
private operator fun String.get(range: IntRange) = this.substring(range)
// 有些时候会得到 724D95122B54EEAC1E214AAAC37259DF.gif
// 需要调整 {724D9512-2B54-EEAC-1E21-4AAAC37259DF}.gif
private fun String.adjustImageId() =
"{${this[0..7]}-${this[8..11]}-${this[12..15]}-${this[16..19]}-${this[20..31]}}.${this.substringAfterLast(".")}"
internal fun ByteReadPacket.readMessage(): Message? { internal fun ByteReadPacket.readMessage(): Message? {
val messageType = this.readByte().toInt() val messageType = this.readByte().toInt()
val sectionLength = this.readShort() val sectionLength = this.readShort()
...@@ -166,7 +175,6 @@ fun MessageChain.toPacket(forGroup: Boolean): ByteReadPacket = buildPacket { ...@@ -166,7 +175,6 @@ fun MessageChain.toPacket(forGroup: Boolean): ByteReadPacket = buildPacket {
*/ */
writeShortLVPacket { writeShortLVPacket {
//todo
writeUByte(0x02u) writeUByte(0x02u)
writeShortLVString(id.value) writeShortLVString(id.value)
writeHex("04 00 04 87 E5 09 3B 05 00 04 D2 C4 C0 B7 06 00 04 00 00 00 50 07 00 01 43 08 00 00 09 00 01 01 0B 00 00 14 00 04 00 00 00 00 15 00 04 00 00 01 ED 16 00 04 00 00 02 17 18 00 04 00 00 EB 34 FF 00 5C 15 36 20 39 32 6B 41 31 43 38 37 65 35 30 39 33 62 64 32 63 34 63 30 62 37 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20") writeHex("04 00 04 87 E5 09 3B 05 00 04 D2 C4 C0 B7 06 00 04 00 00 00 50 07 00 01 43 08 00 00 09 00 01 01 0B 00 00 14 00 04 00 00 00 00 15 00 04 00 00 01 ED 16 00 04 00 00 02 17 18 00 04 00 00 EB 34 FF 00 5C 15 36 20 39 32 6B 41 31 43 38 37 65 35 30 39 33 62 64 32 63 34 63 30 62 37 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20")
...@@ -252,7 +260,7 @@ fun MessageChain.toPacket(forGroup: Boolean): ByteReadPacket = buildPacket { ...@@ -252,7 +260,7 @@ fun MessageChain.toPacket(forGroup: Boolean): ByteReadPacket = buildPacket {
} }
} }
else -> throw UnsupportedOperationException("${this::class.simpleName} is not supported(Full MessageChain=${this@toPacket})") else -> throw UnsupportedOperationException("${this::class.simpleName} is not supported. Do NOT implement Message manually. Full MessageChain=${this@toPacket}")
} }
}) })
} }
......
...@@ -15,10 +15,7 @@ import net.mamoe.mirai.event.subscribe ...@@ -15,10 +15,7 @@ import net.mamoe.mirai.event.subscribe
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.handler.* import net.mamoe.mirai.network.protocol.tim.handler.*
import net.mamoe.mirai.network.protocol.tim.packet.HeartbeatPacket import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.* import net.mamoe.mirai.network.protocol.tim.packet.login.*
import net.mamoe.mirai.network.session import net.mamoe.mirai.network.session
...@@ -213,9 +210,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -213,9 +210,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
} }
packet.use { packet.use {
packet::class.simpleName?.takeIf { !it.endsWith("Encrypted") && !it.endsWith("Raw") }?.let { packet::class.takeUnless { ResponsePacket::class.isInstance(packet) }
bot.logger.verbose("Packet received: $packet") ?.simpleName?.takeUnless { it.endsWith("Encrypted") || it.endsWith("Raw") }
} ?.let {
bot.logger.verbose("Packet received: $packet")
}
// Remove first to release the lock // Remove first to release the lock
handlersLock.withLock { handlersLock.withLock {
...@@ -264,7 +263,13 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -264,7 +263,13 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
} }
} }
bot.logger.verbose("Packet sent: $packet") packet.takeUnless { _ ->
packet.packetId is KnownPacketId && packet.packetId.builder?.let {
it::class.annotations.filterIsInstance<NoLog>().any()
} == true
}?.let {
bot.logger.verbose("Packet sent: $it")
}
PacketSentEvent(bot, packet).broadcast() PacketSentEvent(bot, packet).broadcast()
......
...@@ -11,13 +11,13 @@ import net.mamoe.mirai.getQQ ...@@ -11,13 +11,13 @@ import net.mamoe.mirai.getQQ
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.distributePacket import net.mamoe.mirai.network.distributePacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerFriendOnlineStatusChangedPacket import net.mamoe.mirai.network.protocol.tim.packet.FriendOnlineStatusChangedPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket import net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.SendGroupMessagePacket import net.mamoe.mirai.network.protocol.tim.packet.action.SendGroupMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessageEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.GroupMessageEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.IgnoredServerEventPacket import net.mamoe.mirai.network.protocol.tim.packet.event.IgnoredServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerFriendMessageEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerGroupMessageEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerGroupUploadFileEventPacket import net.mamoe.mirai.network.protocol.tim.packet.event.ServerGroupUploadFileEventPacket
import net.mamoe.mirai.network.qqAccount import net.mamoe.mirai.network.qqAccount
...@@ -36,13 +36,13 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) { ...@@ -36,13 +36,13 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
//todo //todo
} }
is ServerFriendMessageEventPacket -> { is FriendMessageEventPacket -> {
if (!packet.isPrevious) { if (!packet.isPrevious) {
FriendMessageEvent(bot, bot.getQQ(packet.qq), packet.message).broadcast() FriendMessageEvent(bot, bot.getQQ(packet.qq), packet.message).broadcast()
} }
} }
is ServerGroupMessageEventPacket -> { is GroupMessageEventPacket -> {
if (packet.qq == bot.account.id) return if (packet.qq == bot.account.id) return
GroupMessageEvent( GroupMessageEvent(
...@@ -55,8 +55,8 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) { ...@@ -55,8 +55,8 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
).broadcast() ).broadcast()
} }
is ServerFriendOnlineStatusChangedPacket.Encrypted -> distributePacket(packet.decrypt(sessionKey)) is FriendOnlineStatusChangedPacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
is ServerFriendOnlineStatusChangedPacket -> { is FriendOnlineStatusChangedPacket -> {
//TODO //TODO
} }
......
...@@ -15,7 +15,7 @@ import kotlin.properties.Delegates ...@@ -15,7 +15,7 @@ import kotlin.properties.Delegates
* TODO 真的是在线状态改变么 * TODO 真的是在线状态改变么
*/ */
@AnnotatedId(KnownPacketId.SEND_FRIEND_MESSAGE) @AnnotatedId(KnownPacketId.SEND_FRIEND_MESSAGE)
class ServerFriendOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacket(input) { class FriendOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacket(input) {
var qq: UInt by Delegates.notNull() var qq: UInt by Delegates.notNull()
lateinit var status: OnlineStatus lateinit var status: OnlineStatus
...@@ -31,6 +31,7 @@ class ServerFriendOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacke ...@@ -31,6 +31,7 @@ class ServerFriendOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacke
@AnnotatedId(KnownPacketId.SEND_FRIEND_MESSAGE) @AnnotatedId(KnownPacketId.SEND_FRIEND_MESSAGE)
class Encrypted(input: ByteReadPacket) : ServerPacket(input) { class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): ServerFriendOnlineStatusChangedPacket = ServerFriendOnlineStatusChangedPacket(this.decryptBy(sessionKey)).applySequence(sequenceId) fun decrypt(sessionKey: ByteArray): FriendOnlineStatusChangedPacket =
FriendOnlineStatusChangedPacket(this.decryptBy(sessionKey)).applySequence(sequenceId)
} }
} }
\ No newline at end of file
...@@ -8,6 +8,7 @@ import net.mamoe.mirai.utils.io.encryptAndWrite ...@@ -8,6 +8,7 @@ import net.mamoe.mirai.utils.io.encryptAndWrite
import net.mamoe.mirai.utils.io.writeHex import net.mamoe.mirai.utils.io.writeHex
import net.mamoe.mirai.utils.io.writeQQ import net.mamoe.mirai.utils.io.writeQQ
@NoLog
@AnnotatedId(KnownPacketId.HEARTBEAT) @AnnotatedId(KnownPacketId.HEARTBEAT)
object HeartbeatPacket : OutgoingPacketBuilder { object HeartbeatPacket : OutgoingPacketBuilder {
operator fun invoke( operator fun invoke(
...@@ -21,6 +22,7 @@ object HeartbeatPacket : OutgoingPacketBuilder { ...@@ -21,6 +22,7 @@ object HeartbeatPacket : OutgoingPacketBuilder {
} }
} }
@NoLog
@AnnotatedId(KnownPacketId.HEARTBEAT) @AnnotatedId(KnownPacketId.HEARTBEAT)
class Response(input: ByteReadPacket) : ResponsePacket(input) class Response(input: ByteReadPacket) : ResponsePacket(input)
} }
\ No newline at end of file
...@@ -5,6 +5,9 @@ package net.mamoe.mirai.network.protocol.tim.packet ...@@ -5,6 +5,9 @@ package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.IoBuffer import kotlinx.io.core.IoBuffer
import net.mamoe.mirai.network.protocol.tim.packet.NullPacketId.value import net.mamoe.mirai.network.protocol.tim.packet.NullPacketId.value
import net.mamoe.mirai.network.protocol.tim.packet.action.*
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.*
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
...@@ -69,34 +72,38 @@ object NullPacketId : PacketId { ...@@ -69,34 +72,38 @@ object NullPacketId : PacketId {
/** /**
* 未知的 [PacketId] * 未知的 [PacketId]
*/ */
inline class UnknownPacketId(override val value: UShort) : PacketId inline class UnknownPacketId(override inline val value: UShort) : PacketId
/** /**
* 已知的 [PacketId]. 所有在 Mirai 中实现过的包都会使用这些 Id * 已知的 [PacketId]. 所有在 Mirai 中实现过的包都会使用这些 Id
*/ */
enum class KnownPacketId(override val value: UShort) : PacketId { enum class KnownPacketId(override inline val value: UShort, internal inline val builder: OutgoingPacketBuilder?) :
inline TOUCH(0x0825u), PacketId {
inline SESSION_KEY(0x0828u), inline TOUCH(0x0825u, TouchPacket),
inline LOGIN(0X0836u), inline SESSION_KEY(0x0828u, RequestSessionPacket),
inline CAPTCHA(0X00BAU), inline LOGIN(0x0836u, SubmitPasswordPacket),
inline SERVER_EVENT_1(0X00CEU), inline CAPTCHA(0x00BAu, SubmitCaptchaPacket),
inline SERVER_EVENT_2(0X0017U), inline SERVER_EVENT_1(0x00CEu, ServerEventPacket.EventResponse),
inline FRIEND_ONLINE_STATUS_CHANGE(0X0081U), inline SERVER_EVENT_2(0x0017u, ServerEventPacket.EventResponse),
inline CHANGE_ONLINE_STATUS(0x00_ECu), inline FRIEND_ONLINE_STATUS_CHANGE(0x0081u, null),
inline CHANGE_ONLINE_STATUS(0x00_ECu, null),
inline HEARTBEAT(0x0058u),
inline S_KEY(0X001DU), inline HEARTBEAT(0x0058u, HeartbeatPacket),
inline ACCOUNT_INFO(0X005CU), inline S_KEY(0x001Du, RequestSKeyPacket),
inline SEND_GROUP_MESSAGE(0X0002U), inline ACCOUNT_INFO(0x005Cu, RequestAccountInfoPacket),
inline SEND_FRIEND_MESSAGE(0X00CDU), inline SEND_GROUP_MESSAGE(0x0002u, SendGroupMessagePacket),
inline CAN_ADD_FRIEND(0X00A7U), inline SEND_FRIEND_MESSAGE(0x00CDu, SendFriendMessagePacket),
inline GROUP_IMAGE_ID(0X0388U), inline CAN_ADD_FRIEND(0x00A7u, CanAddFriendPacket),
inline FRIEND_IMAGE_ID(0X0352U), inline GROUP_IMAGE_ID(0x0388u, GroupImageIdRequestPacket),
inline FRIEND_IMAGE_ID(0x0352u, FriendImageIdRequestPacket),
inline REQUEST_PROFILE(0x00_31u),
inline SUBMIT_IMAGE_FILE_NAME(0X01_BDu), inline REQUEST_PROFILE(0x00_31u, RequestProfilePicturePacket),
@Suppress("DEPRECATION")
inline SUBMIT_IMAGE_FILE_NAME(0x01_BDu, SubmitImageFilenamePacket),
; ;
override fun toString(): String = builder?.let { it::class.simpleName } ?: this.name
} }
// endregion // endregion
...@@ -109,7 +116,7 @@ enum class KnownPacketId(override val value: UShort) : PacketId { ...@@ -109,7 +116,7 @@ enum class KnownPacketId(override val value: UShort) : PacketId {
@Suppress("unused") @Suppress("unused")
@MustBeDocumented @MustBeDocumented
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.BINARY)
internal annotation class PacketVersion(val date: String, val timVersion: String) internal annotation class PacketVersion(val date: String, val timVersion: String)
private object PacketNameFormatter { private object PacketNameFormatter {
...@@ -124,6 +131,7 @@ private object PacketNameFormatter { ...@@ -124,6 +131,7 @@ private object PacketNameFormatter {
private object IgnoreIdListEquals : List<String> by listOf( private object IgnoreIdListEquals : List<String> by listOf(
"idHex", "idHex",
"id", "id",
"eventIdentity",
"packetId", "packetId",
"sequenceIdInternal", "sequenceIdInternal",
"sequenceId", "sequenceId",
...@@ -152,6 +160,13 @@ private object IgnoreIdListInclude : List<String> by listOf( ...@@ -152,6 +160,13 @@ private object IgnoreIdListInclude : List<String> by listOf(
"RefVolatile" "RefVolatile"
) )
/**
* 带有这个注解的 [Packet], 将不会被记录在 log 中.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class NoLog
/** /**
* 这个方法会翻倍内存占用, 考虑修改. * 这个方法会翻倍内存占用, 考虑修改.
*/ */
...@@ -187,7 +202,7 @@ private fun KProperty<*>.briefDescription(thisRef: Packet): String = ...@@ -187,7 +202,7 @@ private fun KProperty<*>.briefDescription(thisRef: Packet): String =
thisRef, thisRef,
this this
) ?: "[UnknownProperty]" ) ?: "[UnknownProperty]"
else -> value.toString() else -> value.toString().replace("\n", """\n""")
} }
} }
......
...@@ -255,7 +255,7 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder { ...@@ -255,7 +255,7 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
} }
@AnnotatedId(KnownPacketId.FRIEND_IMAGE_ID) @AnnotatedId(KnownPacketId.FRIEND_IMAGE_ID)
@PacketVersion(date = "2019.10.26", timVersion = "2.3.2.21173") @PacketVersion(date = "2019.11.1", timVersion = "2.3.2.21173")
class Response(input: ByteReadPacket) : ResponsePacket(input) { class Response(input: ByteReadPacket) : ResponsePacket(input) {
/** /**
* 访问 HTTP API 时需要使用的一个 key. 128 位 * 访问 HTTP API 时需要使用的一个 key. 128 位
...@@ -289,7 +289,9 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder { ...@@ -289,7 +289,9 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
if (readUByte() != UByte.MIN_VALUE) { if (readUByte() != UByte.MIN_VALUE) {
discardExact(60) discardExact(60)
discardExact(1)//4A, id @Suppress("ControlFlowWithEmptyBody")
while (readUByte().toUInt() != 0x4Au);
uKey = readBytes(readUnsignedVarInt().toInt())//128 uKey = readBytes(readUnsignedVarInt().toInt())//128
discardExact(1)//52, id discardExact(1)//52, id
......
@file:Suppress("EXPERIMENTAL_API_USAGE") @file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.protocol.tim.packet.event package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import net.mamoe.mirai.utils.io.readString import net.mamoe.mirai.utils.io.readString
/** /**
* 群文件上传 * 群文件上传
*/ */
class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity) {
private lateinit var xmlMessage: String private lateinit var xmlMessage: String
override fun decode() { override fun decode() {
...@@ -21,7 +24,58 @@ class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: Eve ...@@ -21,7 +24,58 @@ class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: Eve
}//todo test }//todo test
} }
class ServerGroupUnknownChangedEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { class GroupMemberNickChangedEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity) {
private val groupId: UInt get() = eventIdentity.from
private val group: UInt get() = eventIdentity.from
override fun decode() {
// GroupId VarInt
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 66 00 00 00 05 00 00 00 EE 00 00 00 05
// ? 数据中没有哪个人的昵称改变了
}
}
@PacketVersion(date = "2019.11.2", timVersion = "2.3.2.21173")
class GroupMemberPermissionChangedPacket internal constructor(
input: ByteReadPacket,
eventIdentity: EventPacketIdentity
) :
ServerEventPacket(input, eventIdentity) {
val groupId: UInt get() = eventIdentity.from
var qq: UInt = 0u
lateinit var kind: Kind
enum class Kind {
/**
* 变成管理员
*/
BECOME_OPERATOR,
/**
* 不再是管理员
*/
NO_LONGER_OPERATOR,
} // TODO: 2019/11/2 变成群主的情况
override fun decode(): Unit = with(input) {
// 群里一个人变成管理员:
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 76 E4 B8 DD 01
// 取消管理员
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 00 76 E4 B8 DD 00
discardExact(remaining - 5)
qq = readUInt()
kind = when (readByte().toInt()) {
0x00 -> Kind.NO_LONGER_OPERATOR
0x01 -> Kind.BECOME_OPERATOR
else -> {
error("Could not determine permission change kind")
}
}
}
}
class ServerGroupUnknownChangedEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity) {
override fun decode() = with(input) { override fun decode() = with(input) {
//00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 55 00 00 00 05 00 00 00 E9 00 00 00 05 //00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 55 00 00 00 05 00 00 00 E9 00 00 00 05
......
...@@ -8,7 +8,12 @@ import kotlinx.io.core.readUInt ...@@ -8,7 +8,12 @@ import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.NullMessageChain import net.mamoe.mirai.message.NullMessageChain
import net.mamoe.mirai.message.internal.readMessageChain import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.io.printTLVMap
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readLVByteArray
import net.mamoe.mirai.utils.io.readTLVMap
import kotlin.properties.Delegates import kotlin.properties.Delegates
...@@ -19,7 +24,9 @@ enum class SenderPermission { ...@@ -19,7 +24,9 @@ enum class SenderPermission {
} }
@Suppress("EXPERIMENTAL_API_USAGE") @Suppress("EXPERIMENTAL_API_USAGE")
class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { @PacketVersion(date = "2019.11.2", timVersion = "2.3.2.21173")
class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity) {
var groupNumber: UInt by Delegates.notNull() var groupNumber: UInt by Delegates.notNull()
var qq: UInt by Delegates.notNull() var qq: UInt by Delegates.notNull()
lateinit var senderName: String lateinit var senderName: String
...@@ -41,56 +48,50 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP ...@@ -41,56 +48,50 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP
message = readMessageChain() message = readMessageChain()
val map = readTLVMap(true) val map = readTLVMap(true)
//map.printTLVMap("父map")
if (map.containsKey(18)) { if (map.containsKey(18)) {
map.getValue(18).read { map.getValue(18).read {
val tlv = readTLVMap(true) val tlv = readTLVMap(true)
//tlv.printTLVMap("子map") //tlv.printTLVMap("消息结尾 tag=18 的 TLV")
////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 ////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
//群主的 子map= {5=00 00 00 03, 8=00 00 00 04, 1=48 69 6D 31 38 38 6D 6F 65, 3=04, 4=00 00 00 08} //群主的 子map= {5=00 00 00 03, 8=00 00 00 04, 1=48 69 6D 31 38 38 6D 6F 65, 3=04, 4=00 00 00 08}
//管理员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02, 4=00 00 00 10} //管理员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02, 4=00 00 00 10}
//群成员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02} //群成员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02}
tlv.printTLVMap("Child TLV map") // 4=08, 群主
senderPermission = when (val value0x03 = tlv.getValue(0x03)[0].toUInt()) { // 没有4, 群员
0x04u -> SenderPermission.OWNER // 4=10, 管理员
0x03u -> SenderPermission.MEMBER
0x02u -> {
if (!tlv.containsKey(0x04)) {
SenderPermission.MEMBER
} else when (val value0x04 = tlv.getValue(0x04)[3].toUInt()) {
0x08u -> SenderPermission.OPERATOR
0x10u -> SenderPermission.MEMBER
else -> error("Could not determine member permission, unknown tlv(key=0x04,value=$value0x04)")
}
}
0x01u -> SenderPermission.MEMBER
senderPermission = when (tlv.takeIf { it.containsKey(0x04) }?.get(0x04)?.getOrNull(3)?.toUInt()) {
null -> SenderPermission.MEMBER
0x08u -> SenderPermission.OWNER
0x10u -> SenderPermission.OPERATOR
else -> { else -> {
error("Could not determine member permission, unknown TLV(key=0x03,value=$value0x03;)") tlv.printTLVMap("TLV(tag=18) Map")
//{5=00 00 00 01, 8=00 00 00 01, 1=48 69 6D 31 38 38 6D 6F 65, 3=03} MiraiLogger.warning("Could not determine member permission, default permission MEMBER is being used")
SenderPermission.MEMBER
} }
} }
senderName = when { senderName = when {
tlv.containsKey(0x01) -> kotlinx.io.core.String(tlv.getValue(0x01))//这个人的qq昵称 tlv.containsKey(0x01) -> kotlinx.io.core.String(tlv.getValue(0x01))//这个人的qq昵称
tlv.containsKey(0x02) -> kotlinx.io.core.String(tlv.getValue(0x02))//这个人的群名片 tlv.containsKey(0x02) -> kotlinx.io.core.String(tlv.getValue(0x02))//这个人的群名片
else -> "null" else -> {
tlv.printTLVMap("TLV(tag=18) Map")
MiraiLogger.warning("Could not determine senderName")
"null"
}
} }
} }
} }
} }
} }
fun main() {
"00 00 00 08 00 0A 00 04 01 00 00 00 35 DB 60 A2 01 8D 62 3A B8 02 76 E4 B8 DD 06 B4 B4 BD A8 D5 DF 00 30 34 46 30 41 39 37 31 45 42 37 46 31 42 34 43 33 34 41 31 42 34 33 37 41 35 33 45 31 36 43 30 43 38 35 43 36 44 31 34 46 35 44 31 41 31 43 39 34".printStringFromHex()
}
// //
//以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 //以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
//刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 //刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { class FriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity) {
val qq: UInt get() = eventIdentity.from val qq: UInt get() = eventIdentity.from
/** /**
......
...@@ -59,36 +59,24 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -59,36 +59,24 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
} }
0x002Du -> ServerGroupUploadFileEventPacket(input, eventIdentity) 0x002Du -> ServerGroupUploadFileEventPacket(input, eventIdentity)
0x0052u -> ServerGroupMessageEventPacket(input, eventIdentity) 0x002Cu -> GroupMemberPermissionChangedPacket(input, eventIdentity)
0x00A6u -> ServerFriendMessageEventPacket(input, eventIdentity) /*
*
//0210: 00 00 00 0E 00 08 00 02 00 01 00 0A 00 04 01 00 00 00 00 00 00 06 00 00 00 26 08 02 1A 02 08 49 0A 08 08 00 10 B2 DE 8C ED 05 0A 0C 08 A2 FF 8C F0 03 10 E4 A1 A7 ED 05 0A 0C 08 DD F1 92 B7 07 10 B1 DE 8C ED 05 inline GROUP_MEMBER_NICK_CHANGED(0x002Fu, null),
// 00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E inline GROUP_MEMBER_PERMISSION_CHANGED(0x002Cu, null),
// 00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 07 00 00 00
/*{ */
//todo 02 10 可能是发起会话? 在手机 QQ 打开一个公众号也有这个包; 取消关注公众号也会有这个包; 手机打开某人聊天界面也会有
0x0210u -> discardExact(19) 0x0052u -> GroupMessageEventPacket(input, eventIdentity)
println("type事件" + readUByte().toUInt().toByteArray().toUHexString())
0x00A6u -> FriendMessageEventPacket(input, eventIdentity)
//todo 错了. 可能是 00 79 才是.
ServerFriendTypingCanceledPacket(input, eventIdentity) // "对方正在输入..."
/* 0x0210u -> IgnoredServerEventPacket(input, eventIdentity)
if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity)
else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)*/ else -> {
}*/ UnknownServerEventPacket(type.toByteArray(), true, input, eventIdentity)
0x0210u -> IgnoredServerEventPacket(
eventId = type.toByteArray(),
showData = true,
input = input,
eventIdentity = eventIdentity
)
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
else -> {//0x00 79u, 可能是正在输入的包
MiraiLogger.debug("UnknownEvent type = ${type.toByteArray().toUHexString()}")
UnknownServerEventPacket(input, eventIdentity)
} }
}.applyId(packetId).applySequence(sequenceId) }.applyId(packetId).applySequence(sequenceId)
} }
...@@ -106,6 +94,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -106,6 +94,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
sessionKey: ByteArray sessionKey: ByteArray
): OutgoingPacket = EventResponse(this.packetId, this.sequenceId, bot, sessionKey, this.eventIdentity) ): OutgoingPacket = EventResponse(this.packetId, this.sequenceId, bot, sessionKey, this.eventIdentity)
@NoLog
@Suppress("FunctionName") @Suppress("FunctionName")
object EventResponse : OutgoingPacketBuilder { object EventResponse : OutgoingPacketBuilder {
operator fun invoke( operator fun invoke(
...@@ -128,27 +117,25 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -128,27 +117,25 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
* 忽略的事件 * 忽略的事件
*/ */
@Suppress("unused") @Suppress("unused")
class IgnoredServerEventPacket( class IgnoredServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity)
/**
* Unknown event
*/
class UnknownServerEventPacket(
val eventId: ByteArray, val eventId: ByteArray,
private val showData: Boolean = false, private val showData: Boolean = false,
input: ByteReadPacket, input: ByteReadPacket,
eventIdentity: EventPacketIdentity eventIdentity: EventPacketIdentity
) : ServerEventPacket(input, eventIdentity) { ) :
ServerEventPacket(input, eventIdentity) {
override fun decode() { override fun decode() {
MiraiLogger.debug("UnknownEvent type = ${eventId.toUHexString()}")
if (showData) { if (showData) {
MiraiLogger.debug("IgnoredServerEventPacket data: " + this.input.readBytes().toUHexString()) MiraiLogger.debug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
} else { } else {
this.input.discard() this.input.discard()
} }
} }
} }
\ No newline at end of file
/**
* Unknown event
*/
class UnknownServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
ServerEventPacket(input, eventIdentity) {
override fun decode() {
MiraiLogger.debug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
}
}
...@@ -7,29 +7,29 @@ import net.mamoe.mirai.utils.MiraiLogger ...@@ -7,29 +7,29 @@ import net.mamoe.mirai.utils.MiraiLogger
internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug") internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
internal fun debugPrintln(any: Any?) = DebugLogger.warning(any) internal fun debugPrintln(any: Any?) = DebugLogger.debug(any)
internal fun ByteArray.debugPrint(name: String): ByteArray { internal fun ByteArray.debugPrint(name: String): ByteArray {
DebugLogger.warning(name + "=" + this.toUHexString()) DebugLogger.debug(name + "=" + this.toUHexString())
return this return this
} }
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this")) @Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
internal fun IoBuffer.debugPrint(name: String): IoBuffer { internal fun IoBuffer.debugPrint(name: String): IoBuffer {
val readBytes = this.readBytes() val readBytes = this.readBytes()
DebugLogger.warning(name + "=" + readBytes.toUHexString()) DebugLogger.debug(name + "=" + readBytes.toUHexString())
return readBytes.toIoBuffer() return readBytes.toIoBuffer()
} }
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("discardExact(n)")) @Deprecated("Low efficiency, only for debug purpose", ReplaceWith("discardExact(n)"))
internal fun Input.debugDiscardExact(n: Number, name: String = "") { internal fun Input.debugDiscardExact(n: Number, name: String = "") {
DebugLogger.warning("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString()) DebugLogger.debug("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString())
} }
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this")) @Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket { internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket {
val bytes = this.readBytes() val bytes = this.readBytes()
DebugLogger.warning("ByteReadPacket $name=" + bytes.toUHexString()) DebugLogger.debug("ByteReadPacket $name=" + bytes.toUHexString())
return bytes.toReadPacket() return bytes.toReadPacket()
} }
...@@ -65,7 +65,6 @@ internal fun String.printStringFromHex() { ...@@ -65,7 +65,6 @@ internal fun String.printStringFromHex() {
println(this.hexToBytes().stringOfWitch()) println(this.hexToBytes().stringOfWitch())
} }
internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false, compareTo: String? = null) { internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false, compareTo: String? = null) {
println("Hex比较 `$name`") println("Hex比较 `$name`")
if (compareTo != null) { if (compareTo != null) {
......
...@@ -66,7 +66,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket { ...@@ -66,7 +66,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
CHANGE_ONLINE_STATUS -> ServerLoginSuccessPacket(this) CHANGE_ONLINE_STATUS -> ServerLoginSuccessPacket(this)
CAPTCHA -> ServerCaptchaPacket.Encrypted(this) CAPTCHA -> ServerCaptchaPacket.Encrypted(this)
SERVER_EVENT_1, SERVER_EVENT_2 -> ServerEventPacket.Raw.Encrypted(this, PacketId(id), sequenceId) SERVER_EVENT_1, SERVER_EVENT_2 -> ServerEventPacket.Raw.Encrypted(this, PacketId(id), sequenceId)
FRIEND_ONLINE_STATUS_CHANGE -> ServerFriendOnlineStatusChangedPacket.Encrypted(this) FRIEND_ONLINE_STATUS_CHANGE -> FriendOnlineStatusChangedPacket.Encrypted(this)
S_KEY -> ResponsePacket.Encrypted<RequestSKeyPacket.Response>(this) S_KEY -> ResponsePacket.Encrypted<RequestSKeyPacket.Response>(this)
ACCOUNT_INFO -> ResponsePacket.Encrypted<RequestAccountInfoPacket.Response>(this) ACCOUNT_INFO -> ResponsePacket.Encrypted<RequestAccountInfoPacket.Response>(this)
......
...@@ -7,6 +7,7 @@ import javafx.scene.layout.Region ...@@ -7,6 +7,7 @@ import javafx.scene.layout.Region
import javafx.scene.paint.Color import javafx.scene.paint.Color
import javafx.scene.text.FontWeight import javafx.scene.text.FontWeight
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.io.core.readUInt
import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.stringOfWitch import net.mamoe.mirai.utils.io.stringOfWitch
...@@ -74,7 +75,7 @@ class HexDebuggerGui : View("s") { ...@@ -74,7 +75,7 @@ class HexDebuggerGui : View("s") {
private lateinit var outSize: TextField private lateinit var outSize: TextField
private lateinit var outUVarInt: TextField private lateinit var outUVarInt: TextField
private lateinit var outShort: TextField private lateinit var outShort: TextField
private lateinit var outInt: TextField private lateinit var outUInt: TextField
private lateinit var outString: TextField private lateinit var outString: TextField
...@@ -134,9 +135,9 @@ class HexDebuggerGui : View("s") { ...@@ -134,9 +135,9 @@ class HexDebuggerGui : View("s") {
} }
} }
outInt.text = runOrNull { outUInt.text = runOrNull {
value.hexToBytes().read { value.hexToBytes().read {
readInt().toString() readUInt().toString()
} }
} }
...@@ -192,7 +193,7 @@ class HexDebuggerGui : View("s") { ...@@ -192,7 +193,7 @@ class HexDebuggerGui : View("s") {
label("size") label("size")
label("UVarInt") label("UVarInt")
label("short") label("short")
label("int") label("uint")
label("string") label("string")
children.filterIsInstance<Region>().forEach { children.filterIsInstance<Region>().forEach {
it.fitToParentWidth() it.fitToParentWidth()
...@@ -203,7 +204,7 @@ class HexDebuggerGui : View("s") { ...@@ -203,7 +204,7 @@ class HexDebuggerGui : View("s") {
alignment = Pos.CENTER_RIGHT alignment = Pos.CENTER_RIGHT
outSize = textfield { outSize = textfield {
promptText = "UVarInt" promptText = "Size"
isEditable = false isEditable = false
} }
...@@ -213,17 +214,17 @@ class HexDebuggerGui : View("s") { ...@@ -213,17 +214,17 @@ class HexDebuggerGui : View("s") {
} }
outShort = textfield { outShort = textfield {
promptText = "short" promptText = "Short"
isEditable = false isEditable = false
} }
outInt = textfield { outUInt = textfield {
promptText = "int" promptText = "UInt"
isEditable = false isEditable = false
} }
outString = textfield { outString = textfield {
promptText = "int" promptText = "String"
isEditable = false isEditable = false
} }
......
...@@ -11,6 +11,7 @@ import net.mamoe.mirai.event.Event ...@@ -11,6 +11,7 @@ import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.login import net.mamoe.mirai.login
import net.mamoe.mirai.message.Image
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
import java.io.File import java.io.File
...@@ -47,6 +48,10 @@ suspend fun main() { ...@@ -47,6 +48,10 @@ suspend fun main() {
bot.subscribeMessages { bot.subscribeMessages {
"你好" reply "你好!" "你好" reply "你好!"
has<Image> {
reply(message)
}
startsWith("随机图片", removePrefix = true) { startsWith("随机图片", removePrefix = true) {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
try { try {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment