From ad43a92be46c6c442594cf8e9724c4bef6c69181 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 13 Oct 2019 22:21:26 +0800 Subject: [PATCH] Use PacketHandler.Key --- .../commonMain/kotlin/net.mamoe.mirai/Bot.kt | 15 ++- .../kotlin/net.mamoe.mirai/contact/Group.kt | 3 +- .../kotlin/net.mamoe.mirai/contact/QQ.kt | 3 +- .../message/internal/MessageDataInternal.kt | 43 ++++--- .../network/BotNetworkHandler.kt | 18 +-- .../protocol/tim/TIMBotNetworkHandler.kt | 52 ++++---- .../tim/handler/ActionPacketHandler.kt | 2 + .../tim/handler/EventPacketHandler.kt | 13 ++ .../protocol/tim/handler/PacketHandler.kt | 13 +- .../protocol/tim/packet/ServerEvent.kt | 112 +++++++++++++----- .../action/ClientSendFriendMessagePacket.kt | 8 +- .../utils/ByteReadPacketUtil.kt | 20 ++-- .../kotlin/net.mamoe.mirai/utils/DebugUtil.kt | 13 +- .../net.mamoe.mirai/utils/SocketBridge.kt | 4 +- .../net/mamoe/mirai/utils/SocketBridgeJvm.kt | 14 ++- mirai-debug/src/main/java/HexComparator.kt | 14 +-- 16 files changed, 215 insertions(+), 132 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index b12f3c73e..456b9e99d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -7,8 +7,10 @@ import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler +import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult import net.mamoe.mirai.utils.BotAccount import net.mamoe.mirai.utils.ContactList +import net.mamoe.mirai.utils.LoginConfiguration import net.mamoe.mirai.utils.MiraiLogger /** @@ -44,7 +46,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { val contacts = ContactSystem() - val network: BotNetworkHandler<*> = TIMBotNetworkHandler(this) + var network: BotNetworkHandler<*> = TIMBotNetworkHandler(this) init { instances.add(this) @@ -54,6 +56,17 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { override fun toString(): String = "Bot{id=$id,qq=${account.qqNumber}}" + /** + * [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler.NetworkScope] 下的协程. + * 然后重新启动并尝试登录 + */ + suspend fun reinitializeNetworkHandler(configuration: LoginConfiguration): LoginResult { + logger.logPurple("Reinitializing BotNetworkHandler") + network.close() + network = TIMBotNetworkHandler(this) + return network.login(configuration) + } + /** * Bot 联系人管理. * diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 389e7b98c..f5c1c2e59 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -3,6 +3,7 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.Group.Companion.groupNumberToId import net.mamoe.mirai.message.MessageChain +import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler import net.mamoe.mirai.utils.ContactList import kotlin.jvm.JvmStatic @@ -28,7 +29,7 @@ class Group(bot: Bot, number: Long) : Contact(bot, number) { get() = throw UnsupportedOperationException("Not yet supported") override suspend fun sendMessage(message: MessageChain) { - bot.network.event.sendGroupMessage(this, message) + bot.network[EventPacketHandler].sendGroupMessage(this, message) } override suspend fun sendXMLMessage(message: String) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt index 91fc5b2b9..7e9fec649 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt @@ -4,6 +4,7 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.message.At import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.MessageChain +import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler /** * QQ 账号. @@ -19,7 +20,7 @@ import net.mamoe.mirai.message.MessageChain */ class QQ(bot: Bot, number: Long) : Contact(bot, number) { override suspend fun sendMessage(message: MessageChain) { - bot.network.event.sendFriendMessage(this, message) + bot.network[EventPacketHandler].sendFriendMessage(this, message) } override suspend fun sendXMLMessage(message: String) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/internal/MessageDataInternal.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/internal/MessageDataInternal.kt index 3c5a6e126..2ad125697 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/internal/MessageDataInternal.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/internal/MessageDataInternal.kt @@ -6,7 +6,7 @@ import kotlinx.io.core.* import net.mamoe.mirai.message.* import net.mamoe.mirai.utils.* -internal fun ByteArray.parseMessageFace(): Face = read { +internal fun IoBuffer.parseMessageFace(): Face { //00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0 //00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D discardExact(1) @@ -14,30 +14,30 @@ internal fun ByteArray.parseMessageFace(): Face = read { val id1 = FaceID.ofId(readLVNumber().toInt().toUByte())//可能这个是id, 也可能下面那个 discardExact(readByte().toLong()) readLVNumber()//某id? - return@read Face(id1) + return Face(id1) } -internal fun ByteArray.parsePlainText(): PlainText = read { +internal fun IoBuffer.parsePlainText(): PlainText { discardExact(1) - PlainText(readLVString()) + return PlainText(readLVString()) } -internal fun ByteArray.parseMessageImage0x06(): Image = read { +internal fun IoBuffer.parseMessageImage0x06(): Image { discardExact(1) - MiraiLogger.logDebug("好友的图片") - MiraiLogger.logDebug(this@parseMessageImage0x06.toUHexString()) + this.debugPrint("好友的图片") + //MiraiLogger.logDebug(this.toUHexString()) val filenameLength = readShort() val suffix = readString(filenameLength).substringAfter(".") - discardExact(this@parseMessageImage0x06.size - 37 - 1 - filenameLength - 2) + discardExact(this@parseMessageImage0x06.readRemaining - 37 - 1 - filenameLength - 2) val imageId = readString(36) MiraiLogger.logDebug(imageId) discardExact(1)//0x41 - return@read Image("{$imageId}.$suffix") + return Image("{$imageId}.$suffix") } -internal fun ByteArray.parseMessageImage0x03(): Image = read { +internal fun IoBuffer.parseMessageImage0x03(): Image { discardExact(1) - return@read Image(String(readLVByteArray())) + return Image(String(readLVByteArray())) /* println(String(readLVByteArray())) readTLVMap() @@ -53,14 +53,14 @@ internal fun ByteArray.parseMessageImage0x03(): Image = read { return Image(imageId)*/ } -internal fun ByteArray.parseMessageChain(): MessageChain = read { - readMessageChain() +internal fun ByteReadPacket.parseMessageChain(): MessageChain { + return readMessageChain() } internal fun ByteReadPacket.readMessage(): Message? { val messageType = this.readByte().toInt() val sectionLength = this.readShort().toLong()//sectionLength: short - val sectionData = this.readBytes(sectionLength.toInt())//use buffer instead + val sectionData = this.readIoBuffer(sectionLength.toInt())//use buffer instead return when (messageType) { 0x01 -> sectionData.parsePlainText() 0x02 -> sectionData.parseMessageFace() @@ -68,7 +68,12 @@ internal fun ByteReadPacket.readMessage(): Message? { 0x06 -> sectionData.parseMessageImage0x06() - 0x19 -> {//长文本 + 0x19 -> {//未知, 可能是长文本? + //bot手机自己跟自己发消息会出这个 + //sectionData: 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 + sectionData.readBytes().debugPrint("sectionData") + return PlainText("[UNKNOWN(${this.readBytes().toUHexString()})]") + println() val value = readLVByteArray() //todo 未知压缩算法 PlainText(String(value)) @@ -87,7 +92,6 @@ internal fun ByteReadPacket.readMessage(): Message? { } 0x0E -> { - //null null } @@ -102,16 +106,11 @@ internal fun ByteReadPacket.readMessage(): Message? { fun ByteReadPacket.readMessageChain(): MessageChain { val chain = MessageChain() - var got: Message? = null do { - if (got != null) { - chain.concat(got) - } if (this.remaining == 0L) { return chain } - got = this.readMessage() - } while (got != null) + } while (this.readMessage().takeIf { it != null }?.let { chain.concat(it) } != null) return chain } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt index 87a0f71f3..18f71e33f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt @@ -45,22 +45,14 @@ interface BotNetworkHandler : Closeable { var socket: Socket /** - * 事件处理. 如发送好友消息, 接受群消息并触发事件 + * 得到 [PacketHandler]. + * `get(EventPacketHandler)` 返回 [EventPacketHandler] + * `get(ActionPacketHandler)` 返回 [ActionPacketHandler] */ - val event: EventPacketHandler + operator fun get(key: PacketHandler.Key): T /** - * 动作处理. 如发送好友请求, 处理别人发来的好友请求等 - */ - val action: ActionPacketHandler - - /** - * [PacketHandler] 列表 - */ - val packetHandlers: PacketHandlerList - - /** - * 尝试登录. 将会依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果 + * 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果 */ suspend fun login(configuration: LoginConfiguration): LoginResult diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt index 9a2cb8c8e..2695b4379 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt @@ -24,24 +24,19 @@ import net.mamoe.mirai.utils.* * * @see BotNetworkHandler */ -internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler { +internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler, PacketHandlerList() { override val NetworkScope: CoroutineScope = CoroutineScope(Dispatchers.Default) override lateinit var socket: BotSocket - override lateinit var event: EventPacketHandler - - override lateinit var action: ActionPacketHandler - - override val packetHandlers: PacketHandlerList = PacketHandlerList() - internal val temporaryPacketHandlers = mutableListOf>() private var heartbeatJob: Job? = null + override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*>) { temporaryPacketHandlers.add(temporaryPacketHandler) - temporaryPacketHandler.send(action.session) + temporaryPacketHandler.send(this[ActionPacketHandler].session) } override suspend fun login(configuration: LoginConfiguration): LoginResult { @@ -68,13 +63,11 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler + private val addFriendSessions = mutableListOf() private val uploadImageSessions = mutableListOf() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/EventPacketHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/EventPacketHandler.kt index 67191a64e..73d30c025 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/EventPacketHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/EventPacketHandler.kt @@ -24,6 +24,9 @@ import net.mamoe.mirai.utils.MiraiLogger */ @Suppress("EXPERIMENTAL_API_USAGE") class EventPacketHandler(session: LoginSession) : PacketHandler(session) { + companion object Key : PacketHandler.Key + + internal var ignoreMessage: Boolean = true override suspend fun onPacketReceived(packet: ServerPacket): Unit = with(session) { @@ -57,6 +60,16 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) { //TODO } + is ServerFriendTypingStartedPacket -> { + MiraiLogger.logInfo("${packet.qq.toLong()} 正在输入") + //TODO + } + + is ServerFriendTypingCanceledPacket -> { + MiraiLogger.logInfo("${packet.qq.toLong()} 取消了输入") + //TODO + } + else -> { //ignored } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt index 735b44be3..962ef1b13 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt @@ -12,6 +12,8 @@ abstract class PacketHandler( ) { abstract suspend fun onPacketReceived(packet: ServerPacket) + interface Key + open fun close() { } @@ -19,15 +21,18 @@ abstract class PacketHandler( class PacketHandlerNode( val clazz: KClass, - val instance: T + val instance: T, + val key: PacketHandler.Key ) -fun T.asNode(): PacketHandlerNode { +fun T.asNode(key: PacketHandler.Key): PacketHandlerNode { @Suppress("UNCHECKED_CAST") - return PacketHandlerNode(this::class as KClass, this) + return PacketHandlerNode(this::class as KClass, this, key) } -class PacketHandlerList : MutableList> by mutableListOf() { +open class PacketHandlerList : MutableList> by mutableListOf() { + @Suppress("UNCHECKED_CAST") + operator fun get(key: PacketHandler.Key): T = this.first { it.key === key }.instance as T operator fun get(clazz: KClass): T { this.forEach { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ServerEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ServerEvent.kt index 73e6a16f0..29e937bc7 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ServerEvent.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ServerEvent.kt @@ -14,7 +14,7 @@ data class EventPacketIdentity( val to: UInt,//对于好友消息, 这个是bot internal val uniqueId: IoBuffer//8 ) { - override fun toString(): String = "EPI(from=$from, to=$to)" + override fun toString(): String = "(from=$from, to=$to)" } fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) { @@ -28,11 +28,8 @@ fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = * * @author Him188moe */ -abstract class ServerEventPacket(input: ByteReadPacket, packetId: ByteArray, val eventIdentity: EventPacketIdentity) : ServerPacket(input) { - override val idByteArray: ByteArray = packetId - override var idHex: String = packetId.toUHexString() - - class Raw(input: ByteReadPacket, private val packetId: ByteArray) : ServerPacket(input) { +abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: EventPacketIdentity) : ServerPacket(input) { + class Raw(input: ByteReadPacket) : ServerPacket(input) { fun distribute(): ServerEventPacket = with(input) { val eventIdentity = EventPacketIdentity( @@ -46,25 +43,36 @@ abstract class ServerEventPacket(input: ByteReadPacket, packetId: ByteArray, val "00 C4" -> { discardExact(13) if (readBoolean()) { - ServerAndroidOnlineEventPacket(input, packetId, eventIdentity) + ServerAndroidOfflineEventPacket(input, eventIdentity) } else { - ServerAndroidOfflineEventPacket(input, packetId, eventIdentity) + ServerAndroidOnlineEventPacket(input, eventIdentity) } } - "00 2D" -> ServerGroupUploadFileEventPacket(input, packetId, eventIdentity) + "00 2D" -> ServerGroupUploadFileEventPacket(input, eventIdentity) - "00 52" -> ServerGroupMessageEventPacket(input, packetId, eventIdentity) + "00 52" -> ServerGroupMessageEventPacket(input, eventIdentity) - "00 A6" -> ServerFriendMessageEventPacket(input, packetId, eventIdentity) + "00 A6" -> ServerFriendMessageEventPacket(input.debugPrint("好友消息事件"), eventIdentity) - //"02 10", "00 12" -> ServerUnknownEventPacket(input, packetId, eventIdentity) - else -> UnknownServerEventPacket(input, packetId, eventIdentity) + //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 + "02 10" -> { + discardExact(19) + if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity) + else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity) + } + + //"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity) + + else -> { + MiraiLogger.logDebug("UnknownEvent type = ${type.toUHexString()}") + UnknownServerEventPacket(input, eventIdentity) + } }.setId(idHex) } - class Encrypted(input: ByteReadPacket, private val packetId: ByteArray) : ServerPacket(input) { - fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey), packetId).setId(this.idHex) + class Encrypted(input: ByteReadPacket) : ServerPacket(input) { + fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey)).setId(this.idHex) } } @@ -90,26 +98,45 @@ abstract class ServerEventPacket(input: ByteReadPacket, packetId: ByteArray, val /** * Unknown event */ -class UnknownServerEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) { +class UnknownServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { override fun decode() { - println("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString()) + MiraiLogger.logDebug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString()) } } + +sealed class ServerFriendTypingPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { + val qq get() = eventIdentity.from + +} + +/** + * 对方正在输入 + */ +class ServerFriendTypingStartedPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity) + +/** + * 对方取消了输入 + */ +class ServerFriendTypingCanceledPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity) + + + /** * Android 客户端上线 */ -class ServerAndroidOnlineEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) +class ServerAndroidOnlineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) /** * Android 客户端下线 */ -class ServerAndroidOfflineEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) +class ServerAndroidOfflineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) + /** * 群文件上传 */ -class ServerGroupUploadFileEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) { +class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { private lateinit var xmlMessage: String override fun decode() { @@ -121,7 +148,7 @@ class ServerGroupUploadFileEventPacket(input: ByteReadPacket, packetId: ByteArra } @Suppress("EXPERIMENTAL_API_USAGE") -class ServerGroupMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) { +class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { var groupNumber: UInt by Delegates.notNull() var qq: UInt by Delegates.notNull() lateinit var senderName: String @@ -140,10 +167,11 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, val map = readTLVMap(true) map.printTLVMap("父map") - if (map.containsKey(0x18)) { - senderName = map.getValue(0x18).read { + if (map.containsKey(18)) { + senderName = map.getValue(18).read { val tlv = readTLVMap(true) tlv.printTLVMap("子map") + //群主的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 when { tlv.containsKey(0x01) -> String(tlv.getValue(0x01)) @@ -155,28 +183,48 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, } } -//牛逼[图片]牛逼[图片] 22 96 29 7B B4 DF 94 AA 00 08 74 A4 09 18 8D CC 1F 40 00 52 00 00 00 1B 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 0C 00 05 00 01 00 01 01 22 96 29 7B 01 3E 03 3F A2 00 03 7F 64 5D 7B AC BD 00 00 F3 36 02 03 00 02 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 7B AC BD 12 73 DB A2 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 E7 89 9B E9 80 BC 03 00 CB 02 00 2A 7B 37 41 41 34 42 33 41 41 2D 38 43 33 43 2D 30 46 34 35 2D 32 44 39 42 2D 37 46 33 30 32 41 30 41 43 45 41 41 7D 2E 6A 70 67 04 00 04 B4 52 77 F1 05 00 04 BC EB 03 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 00 41 16 00 04 00 00 00 34 18 00 04 00 00 03 73 FF 00 5C 15 36 20 39 32 6B 41 31 43 62 34 35 32 37 37 66 31 62 63 65 62 30 33 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 7B 37 41 41 34 42 33 41 41 2D 38 43 33 43 2D 30 46 34 35 2D 32 44 39 42 2D 37 46 33 30 32 41 30 41 43 45 41 41 7D 2E 6A 70 67 41 01 00 09 01 00 06 E7 89 9B E9 80 BC 03 00 77 02 00 2A 7B 37 41 41 34 42 33 41 41 2D 38 43 33 43 2D 30 46 34 35 2D 32 44 39 42 2D 37 46 33 30 32 41 30 41 43 45 41 41 7D 2E 6A 70 67 04 00 04 B4 52 77 F1 05 00 04 BC EB 03 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 00 41 16 00 04 00 00 00 34 18 00 04 00 00 03 73 FF 00 08 15 37 20 20 38 41 41 41 0E 00 0E 01 00 04 00 00 00 09 07 00 04 00 00 00 01 19 00 35 01 00 32 AA 02 2F 50 03 60 00 68 00 9A 01 26 08 09 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 05 00 04 00 00 00 01 08 00 04 00 00 00 01 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 -//牛逼[图片]牛逼 22 96 29 7B B4 DF 94 AA 00 0B C1 0A 09 18 89 93 1F 40 00 52 00 00 00 1B 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 0C 00 05 00 01 00 01 01 22 96 29 7B 01 3E 03 3F A2 00 03 7E F5 5D 7B 97 E7 00 00 F3 32 01 8D 00 02 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 7B 97 E6 FA BE 7F DC 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 E7 89 9B E9 80 BC 03 00 CF 02 00 2A 7B 39 44 32 44 45 39 31 41 2D 33 39 38 39 2D 39 35 35 43 2D 44 35 42 34 2D 37 46 41 32 37 38 39 37 38 36 30 39 7D 2E 6A 70 67 04 00 04 97 15 7F 03 05 00 04 79 5C B1 A3 06 00 04 00 00 00 50 07 00 01 41 08 00 00 09 00 01 01 0B 00 00 14 00 04 03 00 00 00 15 00 04 00 00 00 3C 16 00 04 00 00 00 40 18 00 04 00 00 03 CC FF 00 60 15 36 20 39 36 6B 45 31 41 39 37 31 35 37 66 30 33 37 39 35 63 62 31 61 33 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 39 44 32 44 45 39 31 41 2D 33 39 38 39 2D 39 35 35 43 2D 44 35 42 34 2D 37 46 41 32 37 38 39 37 38 36 30 39 7D 2E 6A 70 67 31 32 31 32 41 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 0E 01 00 04 00 00 00 09 07 00 04 00 00 00 01 19 00 35 01 00 32 AA 02 2F 50 03 60 00 68 00 9A 01 26 08 09 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 05 00 04 00 00 00 01 08 00 04 00 00 00 01 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 +// +//以前的消息: 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 -class ServerFriendMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) { - val group: UInt get() = eventIdentity.from - val qq: UInt get() = eventIdentity.to +fun main() { + println("08 02 1A 12 08 95 02 10 90 04 40 D6 DE 8C ED 05 48 CF B5 90 D6 02 08 DD F1 92 B7 07 10 DD F1 92 B7 07 1A 14 08 00 10 05 18 D6 DE 8C ED 05 20 02 28 FF FF FF FF 0F 32 00".hexToBytes().stringOf()) +} + +fun main2() { + val data = "00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00".hexToBytes() + val packet = ServerFriendMessageEventPacket(data.toReadPacket(), EventPacketIdentity(0u, 0u, IoBuffer.Empty)) + packet.decode() + println(packet) +} + +class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { + val qq: UInt get() = eventIdentity.from + + /** + * 是否是在这次登录之前的消息, 即消息记录 + */ + var isPrevious: Boolean = false lateinit var message: MessageChain - //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 E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 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 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00 override fun decode() = with(input) { input.discardExact(2) val l1 = readShort() - discardExact(l1.toInt()) + discardExact(1)//0x00 + isPrevious = readByte().toInt() == 0x08 + discardExact(l1.toInt() - 2) discardExact(69) readLVByteArray()//font discardExact(2)//2个0x00 message = readMessageChain() val map: Map = readTLVMap(true).withDefault { byteArrayOf() } - println("map.getValue(18)=" + map.getValue(18)) + map.printTLVMap("readTLVMap") + //println("map.getValue(18)=" + map.getValue(18).toUHexString()) //19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01 @@ -232,7 +280,7 @@ B1 89 BE 09 8F 00 1A E5 00 0B 03 A2 09 90 BB 7A 1F 40 00 A6 00 00 00 20 00 05 00 backup -class ServerFriendMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) { +class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { var qq: Long = 0 lateinit var event: String diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt index 6240cf9ca..ebfb5a796 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt @@ -18,12 +18,12 @@ class ClientSendFriendMessagePacket( private val message: MessageChain ) : ClientPacket() { override fun encode(builder: BytePacketBuilder) = with(builder) { - this.writeRandom(2) + writeRandom(2) - this.writeQQ(botQQ) - this.writeHex(TIMProtocol.fixVer2) + writeQQ(botQQ) + writeHex(TIMProtocol.fixVer2) - this.encryptAndWrite(sessionKey) { + encryptAndWrite(sessionKey) { writeQQ(botQQ) writeQQ(targetQQ) writeHex("00 00 00 08 00 01 00 04 00 00 00 00") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ByteReadPacketUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ByteReadPacketUtil.kt index 018cacca3..baea3b905 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ByteReadPacketUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ByteReadPacketUtil.kt @@ -86,7 +86,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {//TODO 优化 "00 BA" -> ServerCaptchaPacket.Encrypted(this, idHex) - "00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(this, idHex.hexToBytes()) + "00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(this) "00 81" -> ServerFieldOnlineStatusChangedPacket.Encrypted(this) @@ -102,7 +102,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {//TODO 优化 }.setId(idHex) } -fun ByteReadPacket.readIP(): String = buildString(4 + 3) { +fun Input.readIP(): String = buildString(4 + 3) { repeat(4) { val byte = readUByte() this.append(byte.toString()) @@ -110,11 +110,11 @@ fun ByteReadPacket.readIP(): String = buildString(4 + 3) { } } -fun ByteReadPacket.readLVString(): String = String(this.readLVByteArray()) +fun Input.readLVString(): String = String(this.readLVByteArray()) -fun ByteReadPacket.readLVByteArray(): ByteArray = this.readBytes(this.readShort().toInt()) +fun Input.readLVByteArray(): ByteArray = this.readBytes(this.readShort().toInt()) -fun ByteReadPacket.readTLVMap(expectingEOF: Boolean = false): Map { +fun Input.readTLVMap(expectingEOF: Boolean = false): Map { val map = mutableMapOf() var type: UByte @@ -144,11 +144,11 @@ fun ByteReadPacket.readTLVMap(expectingEOF: Boolean = false): Map.printTLVMap(name: String) = debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() }) -fun ByteReadPacket.readString(length: Number): String = String(this.readBytes(length.toInt())) +fun Input.readString(length: Number): String = String(this.readBytes(length.toInt())) private const val TRUE_BYTE_VALUE: Byte = 1 -fun ByteReadPacket.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE -fun ByteReadPacket.readLVNumber(): Number { +fun Input.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE +fun Input.readLVNumber(): Number { return when (this.readShort().toInt()) { 1 -> this.readByte() 2 -> this.readShort() @@ -161,7 +161,7 @@ fun ByteReadPacket.readLVNumber(): Number { //添加@JvmSynthetic 导致 idea 无法检查这个文件的错误 //@JvmSynthetic @Deprecated("Low efficiency", ReplaceWith("")) -fun ByteReadPacket.gotoWhere(matcher: UByteArray): ByteReadPacket { +fun I.gotoWhere(matcher: UByteArray): I { return this.gotoWhere(matcher.toByteArray()) } @@ -169,7 +169,7 @@ fun ByteReadPacket.gotoWhere(matcher: UByteArray): ByteReadPacket { * 去往下一个含这些连续字节的位置 */ @Deprecated("Low efficiency", ReplaceWith("")) -fun ByteReadPacket.gotoWhere(matcher: ByteArray): ByteReadPacket { +fun I.gotoWhere(matcher: ByteArray): I { require(matcher.isNotEmpty()) loop@ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DebugUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DebugUtil.kt index 6e8a9864d..f062582a2 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DebugUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DebugUtil.kt @@ -1,5 +1,6 @@ package net.mamoe.mirai.utils +import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.Input import kotlinx.io.core.IoBuffer import kotlinx.io.core.readBytes @@ -9,20 +10,26 @@ internal object DebugLogger : MiraiLogger by PlatformLogger("Packet Debug") internal fun debugPrintln(any: Any?) = DebugLogger.logPurple(any) -@Deprecated("Debugging Warning", ReplaceWith("")) internal fun ByteArray.debugPrint(name: String): ByteArray { DebugLogger.logPurple(name + "=" + this.toUHexString()) return this } -@Deprecated("Debugging Warning", ReplaceWith("")) +@Deprecated("Low Efficiency", ReplaceWith("")) internal fun IoBuffer.debugPrint(name: String): IoBuffer { val readBytes = this.readBytes() DebugLogger.logPurple(name + "=" + readBytes.toUHexString()) return readBytes.toIoBuffer() } -@Deprecated("Debugging Warning", ReplaceWith("")) +@Deprecated("Low Efficiency", ReplaceWith("discardExact(n)")) internal fun Input.debugDiscardExact(n: Number, name: String = "") { DebugLogger.logPurple("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString()) } + +@Deprecated("Low Efficiency", ReplaceWith("")) +internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket { + val bytes = this.readBytes() + DebugLogger.logPurple("ByteReadPacket $name=" + bytes.toUHexString()) + return bytes.toReadPacket() +} diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SocketBridge.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SocketBridge.kt index f51081f0d..2401e1537 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SocketBridge.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SocketBridge.kt @@ -11,4 +11,6 @@ expect class MiraiDatagramChannel(serverHost: String, serverPort: Short) : Close val isOpen: Boolean } -expect class ClosedChannelException : IOException \ No newline at end of file +expect class ClosedChannelException : IOException + +expect class SendPacketInternalException(cause: Throwable?) : Exception \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SocketBridgeJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SocketBridgeJvm.kt index 809903b6c..b391d978c 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SocketBridgeJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SocketBridgeJvm.kt @@ -14,7 +14,15 @@ actual class MiraiDatagramChannel actual constructor(serverHost: String, serverP private val channel: DatagramChannel = DatagramChannel.open().connect(serverAddress) actual suspend fun read(buffer: IoBuffer) = withContext(Dispatchers.IO) { (channel as ReadableByteChannel).read(buffer) } - actual suspend fun send(buffer: IoBuffer) = withContext(Dispatchers.IO) { buffer.readDirect { channel.send(it, serverAddress) } } + actual suspend fun send(buffer: IoBuffer) = withContext(Dispatchers.IO) { + buffer.readDirect { + try { + channel.send(it, serverAddress) + } catch (e: Exception) { + throw SendPacketInternalException(e) + } + } + } override fun close() { channel.close() @@ -23,4 +31,6 @@ actual class MiraiDatagramChannel actual constructor(serverHost: String, serverP actual val isOpen: Boolean get() = channel.isOpen } -actual typealias ClosedChannelException = java.nio.channels.ClosedChannelException \ No newline at end of file +actual typealias ClosedChannelException = java.nio.channels.ClosedChannelException + +actual class SendPacketInternalException actual constructor(cause: Throwable?) : Exception(cause) \ No newline at end of file diff --git a/mirai-debug/src/main/java/HexComparator.kt b/mirai-debug/src/main/java/HexComparator.kt index 557fda074..ea6f8b2a7 100644 --- a/mirai-debug/src/main/java/HexComparator.kt +++ b/mirai-debug/src/main/java/HexComparator.kt @@ -20,14 +20,10 @@ import kotlin.math.max object HexComparator { private val RED = "\u001b[31m" - private val GREEN = "\u001b[33m" - private val UNKNOWN = "\u001b[30m" - private val BLUE = "\u001b[34m" - private val clipboardString: String? get() { val trans = Toolkit.getDefaultToolkit().systemClipboard.getContents(null) @@ -44,7 +40,6 @@ object HexComparator { } class ConstMatcher constructor(hex: String) { - private val matches = LinkedList() object TestConsts { @@ -59,6 +54,7 @@ object HexComparator { val _Him188moe_ = "Him188moe".toByteArray().toUHexString() val 发图片 = "发图片".toByteArray().toUHexString() val 群 = "群".toByteArray().toUHexString() + val 你好 = "你好".toByteArray().toUHexString() val SINGLE_PLAIN_MESSAGE_HEAD = "00 00 01 00 09 01" @@ -69,7 +65,8 @@ object HexComparator { @Suppress("SpellCheckingInspection") object PacketIds { val heartbeat = "00 58" - val friendmsg = "00 CD" + val friendmsgsend = "00 CD" + val friendmsgevent = "00 CE" } init { @@ -104,7 +101,6 @@ object HexComparator { } } - private fun match(hex: String, field: Field): List { val constValue: String try { @@ -293,6 +289,10 @@ object HexComparator { } fun main() { +// println(HexComparator.colorize("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 E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 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")) + + + val scanner = Scanner(System.`in`) while (true) { println("Hex1: ")