diff --git a/docs/Messages.md b/docs/Messages.md index f7425784e..3703492e7 100644 --- a/docs/Messages.md +++ b/docs/Messages.md @@ -89,6 +89,7 @@ Mirai 支持多种消息类型。 [`MusicShare`]: ../mirai-core-api/src/commonMain/kotlin/message/data/MusicShare.kt [`Dice`]: ../mirai-core-api/src/commonMain/kotlin/message/data/Dice.kt [`FileMessage`]: ../mirai-core-api/src/commonMain/kotlin/message/data/FileMessage.kt +[`RockPaperScissors`]: ../mirai-core-api/src/commonMain/kotlin/message/data/RockPaperScissors.kt [`MessageSource`]: ../mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt [`QuoteReply`]: ../mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt @@ -119,6 +120,7 @@ Mirai 支持多种消息类型。 | [`SimpleServiceMessage`] | (不稳定)服务消息 | `$content` | 2.0 | | [`MusicShare`] | 音乐分享 | `[分享]曲名` | 2.1 | | [`Dice`] | 魔法表情骰子 | `[骰子:$value]` | 2.5 | +| [`RockPaperScissors`] | 魔法表情猜拳 | `[石头]`/`[剪刀]`/`[布]` | 2.14 | | [`FileMessage`] | 文件消息 | `[文件]文件名称` | 2.5 | | [`Audio`] | 语音 | `[语音消息]` | 2.7 | @@ -572,6 +574,7 @@ at.serializeToMiraiCode() // 结果为 `[mirai:at:123]` | [`Dice`] | `[mirai:dice:$value]` | | [`MusicShare`] | `[mirai:musicshare:$args]` | | [`FileMessage`] | `[mirai:file:$id,$internalId,$name,$size]` | +| [`RockPaperScissors`] | `[mirai:rps:$name]` | ### 由 mirai 码字符串取得 `MessageChain` 实例 diff --git a/mirai-core-api/compatibility-validation/android/api/android.api b/mirai-core-api/compatibility-validation/android/api/android.api index 55316d25e..6588a8d4e 100644 --- a/mirai-core-api/compatibility-validation/android/api/android.api +++ b/mirai-core-api/compatibility-validation/android/api/android.api @@ -5112,6 +5112,32 @@ public final class net/mamoe/mirai/message/data/RichMessageOrigin$Key : net/mamo public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public final class net/mamoe/mirai/message/data/RockPaperScissors : java/lang/Enum, net/mamoe/mirai/message/code/CodableMessage, net/mamoe/mirai/message/data/MarketFace { + public static final field Key Lnet/mamoe/mirai/message/data/RockPaperScissors$Key; + public static final field PAPER Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final field ROCK Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final field SCISSORS Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final field SERIAL_NAME Ljava/lang/String; + public fun contentToString ()Ljava/lang/String; + public final fun eliminates (Lnet/mamoe/mirai/message/data/RockPaperScissors;)Ljava/lang/Boolean; + public final fun getContent ()Ljava/lang/String; + public fun getId ()I + public final fun getInternalId ()B + public synthetic fun getName ()Ljava/lang/String; + public static final fun random ()Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final fun random (Lkotlin/random/Random;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public fun toString ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static fun values ()[Lnet/mamoe/mirai/message/data/RockPaperScissors; +} + +public final class net/mamoe/mirai/message/data/RockPaperScissors$Key : net/mamoe/mirai/message/data/AbstractPolymorphicMessageKey { + public final fun random ()Lnet/mamoe/mirai/message/data/RockPaperScissors; + public final fun random (Lkotlin/random/Random;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static synthetic fun random$default (Lnet/mamoe/mirai/message/data/RockPaperScissors$Key;Lkotlin/random/Random;ILjava/lang/Object;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public abstract interface class net/mamoe/mirai/message/data/ServiceMessage : net/mamoe/mirai/message/code/CodableMessage, net/mamoe/mirai/message/data/RichMessage { public static final field Key Lnet/mamoe/mirai/message/data/ServiceMessage$Key; public abstract fun getServiceId ()I diff --git a/mirai-core-api/compatibility-validation/jvm/api/jvm.api b/mirai-core-api/compatibility-validation/jvm/api/jvm.api index 1d69ea44e..719a03766 100644 --- a/mirai-core-api/compatibility-validation/jvm/api/jvm.api +++ b/mirai-core-api/compatibility-validation/jvm/api/jvm.api @@ -5112,6 +5112,32 @@ public final class net/mamoe/mirai/message/data/RichMessageOrigin$Key : net/mamo public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public final class net/mamoe/mirai/message/data/RockPaperScissors : java/lang/Enum, net/mamoe/mirai/message/code/CodableMessage, net/mamoe/mirai/message/data/MarketFace { + public static final field Key Lnet/mamoe/mirai/message/data/RockPaperScissors$Key; + public static final field PAPER Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final field ROCK Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final field SCISSORS Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final field SERIAL_NAME Ljava/lang/String; + public fun contentToString ()Ljava/lang/String; + public final fun eliminates (Lnet/mamoe/mirai/message/data/RockPaperScissors;)Ljava/lang/Boolean; + public final fun getContent ()Ljava/lang/String; + public fun getId ()I + public final fun getInternalId ()B + public synthetic fun getName ()Ljava/lang/String; + public static final fun random ()Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static final fun random (Lkotlin/random/Random;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public fun toString ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static fun values ()[Lnet/mamoe/mirai/message/data/RockPaperScissors; +} + +public final class net/mamoe/mirai/message/data/RockPaperScissors$Key : net/mamoe/mirai/message/data/AbstractPolymorphicMessageKey { + public final fun random ()Lnet/mamoe/mirai/message/data/RockPaperScissors; + public final fun random (Lkotlin/random/Random;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public static synthetic fun random$default (Lnet/mamoe/mirai/message/data/RockPaperScissors$Key;Lkotlin/random/Random;ILjava/lang/Object;)Lnet/mamoe/mirai/message/data/RockPaperScissors; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public abstract interface class net/mamoe/mirai/message/data/ServiceMessage : net/mamoe/mirai/message/code/CodableMessage, net/mamoe/mirai/message/data/RichMessage { public static final field Key Lnet/mamoe/mirai/message/data/ServiceMessage$Key; public abstract fun getServiceId ()I diff --git a/mirai-core-api/src/commonMain/kotlin/message/code/internal/impl.kt b/mirai-core-api/src/commonMain/kotlin/message/code/internal/impl.kt index c44ebeb85..b8834f062 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/code/internal/impl.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/code/internal/impl.kt @@ -123,6 +123,9 @@ private object MiraiCodeParsers : AbstractMap<String, MiraiCodeParser>(), Map<St "dice" to MiraiCodeParser(Regex("""([1-6])""")) { (value) -> Dice(value.toInt()) }, + "rps" to MiraiCodeParser(Regex("""(\w+)""")) { (value) -> + RockPaperScissors.valueOf(value.uppercase()) + }, "musicshare" to MiraiCodeParser.DynamicParser(7) { args -> val (kind, title, summary, jumpUrl, pictureUrl) = args val musicUrl = args[5] diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/RockPaperScissors.kt b/mirai-core-api/src/commonMain/kotlin/message/data/RockPaperScissors.kt new file mode 100644 index 000000000..29d8a2a8b --- /dev/null +++ b/mirai-core-api/src/commonMain/kotlin/message/data/RockPaperScissors.kt @@ -0,0 +1,116 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +@file:JvmMultifileClass +@file:JvmName("MessageUtils") + +package net.mamoe.mirai.message.data + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.mamoe.mirai.message.code.CodableMessage +import net.mamoe.mirai.message.data.RockPaperScissors.* +import net.mamoe.mirai.message.data.visitor.MessageVisitor +import net.mamoe.mirai.utils.* +import kotlin.jvm.* +import kotlin.random.Random + +/** + * 石头剪刀布. + * + * 可以通过 [RockPaperScissors.random] 获得一个随机手势的实例. + * + * @property ROCK 石头 `[mirai:rps:rock]` + * @property SCISSORS 剪刀 `[mirai:rps:scissors]` + * @property PAPER 布(纸)`[mirai:rps:paper]` + * + * @since 2.14 + */ +@kotlin.Suppress("RemoveRedundantQualifierName") +@Serializable(RockPaperScissors.Serializer::class) +@SerialName(RockPaperScissors.SERIAL_NAME) +public enum class RockPaperScissors( + public val content: String, + + internalId: Int, +) : MarketFace, CodableMessage { + ROCK("[石头]", 48), + SCISSORS("[剪刀]", 49), + PAPER("[布]", 50) + ; + + @MiraiExperimentalApi + override val id: Int + get() = 11415 + + @MiraiInternalApi + @JvmSynthetic + public val internalId: Byte = internalId.toByte() + + @MiraiExperimentalApi + override fun appendMiraiCodeTo(builder: StringBuilder) { + builder.append("[mirai:rps:").append(name.lowercase()).append(']') + } + + override fun toString(): String = serializeToMiraiCode() + + + override fun contentToString(): String = content + + @MiraiInternalApi + override fun <D, R> accept(visitor: MessageVisitor<D, R>, data: D): R { + return visitor.visitRockPaperScissors(this, data) + } + + /** + * 判断 当前手势 (`this`) 能否淘汰对手 ([other]) + * + * @return 赢返回 `true`,输返回 `false`,平局时返回 `null` + */ + public infix fun eliminates(other: RockPaperScissors): Boolean? { + return when { + this == other -> null + this == ROCK && other == SCISSORS -> true + this == SCISSORS && other == PAPER -> true + this == PAPER && other == ROCK -> true + else -> false + } + } + + public companion object Key : + AbstractPolymorphicMessageKey<MarketFace, RockPaperScissors>(MarketFace, { it.safeCast() }) { + public const val SERIAL_NAME: String = "RockPaperScissors" + + private val values = values() + + /** + * 获取随机手势的 [石头剪刀布][RockPaperScissors] + * + * Java 可通过 `kotlin.random.PlatformRandomKt.asKotlinRandom()` 来传入一个 random + */ + @JvmStatic + @JvmOverloads + public fun random(random: Random = Random): RockPaperScissors = RockPaperScissors.values.random(random) + + } + + internal object Serializer : KSerializer<RockPaperScissors> by Surrogate.serializer().map( + resultantDescriptor = Surrogate.serializer().descriptor.copy(SERIAL_NAME), + deserialize = { valueOf(it.name) }, + serialize = { Surrogate(name) }, + ) { + + @Serializable + @SerialName(RockPaperScissors.SERIAL_NAME) + private class Surrogate( + val name: String, + ) + } +} diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/visitor/MessageVisitor.kt b/mirai-core-api/src/commonMain/kotlin/message/data/visitor/MessageVisitor.kt index 234a05885..9c072fc2a 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/visitor/MessageVisitor.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/visitor/MessageVisitor.kt @@ -48,6 +48,7 @@ public interface MessageVisitor<in D, out R> { // region MarketFace public fun visitMarketFace(message: MarketFace, data: D): R public fun visitDice(message: Dice, data: D): R + public fun visitRockPaperScissors(message: RockPaperScissors, data: D): R // endregion // endregion @@ -184,6 +185,10 @@ public abstract class AbstractMessageVisitor<in D, out R> : MessageVisitor<D, R> return visitMarketFace(message, data) } + public override fun visitRockPaperScissors(message: RockPaperScissors, data: D): R { + return visitMarketFace(message, data) + } + public override fun visitFace(message: Face, data: D): R { return visitMessageContent(message, data) } diff --git a/mirai-core-api/src/commonTest/kotlin/message.data/MessageVisitorTest.kt b/mirai-core-api/src/commonTest/kotlin/message.data/MessageVisitorTest.kt index 5fbb1d1ce..97d0b4d8c 100644 --- a/mirai-core-api/src/commonTest/kotlin/message.data/MessageVisitorTest.kt +++ b/mirai-core-api/src/commonTest/kotlin/message.data/MessageVisitorTest.kt @@ -107,6 +107,10 @@ internal class MessageVisitorTest { return arrayOf("visitDice") + super.visitDice(message, data) } + override fun visitRockPaperScissors(message: RockPaperScissors, data: Unit): Array<String> { + return arrayOf("visitRockPaperScissors") + super.visitRockPaperScissors(message, data) + } + override fun visitFace(message: Face, data: Unit): Array<String> { return arrayOf("visitFace") + super.visitFace(message, data) } @@ -335,6 +339,18 @@ internal class MessageVisitorTest { Dice(1).accept(GetCalledMethodNames) ) + assertContentEquals( + arrayOf( + "visitRockPaperScissors", + "visitMarketFace", + "visitHummerMessage", + "visitMessageContent", + "visitSingleMessage", + "visitMessage", + ), + RockPaperScissors.PAPER.accept(GetCalledMethodNames) + ) + assertContentEquals( arrayOf( diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt index 4e914a5c8..b04f046e9 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt @@ -28,6 +28,7 @@ import net.mamoe.mirai.utils.map internal class MarketFaceProtocol : MessageProtocol() { override fun ProcessorCollector.collectProcessorsImpl() { add(DiceEncoder()) + add(RockPaperScissorsEncoder()) add(MarketFaceImplEncoder()) add(MarketFaceDecoder()) @@ -46,11 +47,12 @@ internal class MarketFaceProtocol : MessageProtocol() { MarketFace::class, MarketFaceImpl.serializer().map( resultantDescriptor = MarketFaceImpl.serializer().descriptor.copy(MarketFace.SERIAL_NAME), deserialize = { - it.delegate.toDiceOrNull() ?: it + it.delegate.toDiceOrNull() ?: it.delegate.toRockPaperScissorsOrNull() ?: it }, serialize = { when (it) { is Dice -> MarketFaceImpl(it.toJceStruct()) + is RockPaperScissors -> MarketFaceImpl(it.toJceStruct()) is MarketFaceImpl -> it else -> { error("Unsupported MarketFace type ${it::class.qualifiedName}") @@ -64,6 +66,7 @@ internal class MarketFaceProtocol : MessageProtocol() { MessageSerializer.superclassesScope(MarketFace::class, MessageContent::class, SingleMessage::class) { add(MessageSerializer(MarketFaceImpl::class, MarketFaceImpl.serializer())) add(MessageSerializer(Dice::class, Dice.serializer())) + add(MessageSerializer(RockPaperScissors::class, RockPaperScissors.serializer())) } } @@ -90,6 +93,13 @@ internal class MarketFaceProtocol : MessageProtocol() { } } + private class RockPaperScissorsEncoder : MessageEncoder<RockPaperScissors> { + override suspend fun MessageEncoderContext.process(data: RockPaperScissors) { + markAsConsumed() + processAlso(MarketFaceImpl(data.toJceStruct())) + } + } + private class MarketFaceDecoder : MessageDecoder { override suspend fun MessageDecoderContext.process(data: ImMsgBody.Elem) { val proto = data.marketFace ?: return @@ -99,6 +109,11 @@ internal class MarketFaceProtocol : MessageProtocol() { return } + proto.toRockPaperScissorsOrNull()?.let { + collect(it) + return + } + collect(MarketFaceImpl(proto)) } } @@ -118,6 +133,12 @@ internal class MarketFaceProtocol : MessageProtocol() { 6 to "7A2303AD80755FCB6BBFAC38327E0C01".hexToBytes(), ) + private val RPS_PC_FACE_IDS = mapOf( + 48 to "E5D889F1DF79B2B45183F625584465D3".hexToBytes(), + 49 to "628FA4AB7B6C2BCCFCDCD0C2DAF7A60C".hexToBytes(), + 50 to "457CDE420F598EB424CED2E905D38D8B".hexToBytes(), + ) + private fun ImMsgBody.MarketFace.toDiceOrNull(): Dice? { if (this.tabId != 11464) return null val value = when { @@ -130,6 +151,26 @@ internal class MarketFaceProtocol : MessageProtocol() { return null } + private fun ImMsgBody.MarketFace.toRockPaperScissorsOrNull(): RockPaperScissors? { + if (tabId != 11415) return null + + val value = when { + mobileParam.isNotEmpty() -> { + val theLast = mobileParam.lastOrNull() ?: return null + theLast.toInt().and(0xff) + } + else -> RPS_PC_FACE_IDS.entries.find { it.value.contentEquals(faceId) }?.key ?: return null + } + + return when (value) { + 48 -> RockPaperScissors.ROCK + 49 -> RockPaperScissors.SCISSORS + 50 -> RockPaperScissors.PAPER + + else -> null + } + } + // From https://github.com/mamoe/mirai/issues/1012 private fun Dice.toJceStruct(): ImMsgBody.MarketFace { return ImMsgBody.MarketFace( @@ -161,5 +202,31 @@ internal class MarketFaceProtocol : MessageProtocol() { ) ) } + + private fun RockPaperScissors.toJceStruct(): ImMsgBody.MarketFace { + return ImMsgBody.MarketFace( + faceName = byteArrayOf(91, -25, -116, -100, -26, -117, -77, 93), + itemType = 6, + faceInfo = 1, + faceId = byteArrayOf( + -125, -56, -94, -109, -82, + 101, -54, 20, 15, 52, + -127, 32, -89, 116, 72, -18 + ), + tabId = 11415, + subType = 3, + key = byteArrayOf(55, 100, 101, 51, 57, 102, 101, 98, 99, 102, 52, 53, 101, 54, 100, 98), + mediaType = 0, + imageWidth = 200, + imageHeight = 200, + mobileParam = byteArrayOf( + 114, 115, 99, 84, 121, 112, 101, + 63, 49, 59, 118, 97, 108, 117, + 101, 61, + internalId + ), + pbReserve = byteArrayOf(10, 6, 8, -56, 1, 16, -56, 1, 64, 1) + ) + } } } diff --git a/mirai-core/src/commonTest/kotlin/message/code/TestMiraiCode.kt b/mirai-core/src/commonTest/kotlin/message/code/TestMiraiCode.kt index 403d00a63..e9b97646e 100644 --- a/mirai-core/src/commonTest/kotlin/message/code/TestMiraiCode.kt +++ b/mirai-core/src/commonTest/kotlin/message/code/TestMiraiCode.kt @@ -82,5 +82,18 @@ internal class TestMiraiCode : AbstractTest() { brief = "", ) assertEquals(musicShare.toMessageChain(), musicShare.serializeToMiraiCode().deserializeMiraiCode()) + + assertEquals( + messageChainOf(RockPaperScissors.ROCK), + "[mirai:rps:rock]".deserializeMiraiCode() + ) + assertEquals( + messageChainOf(RockPaperScissors.SCISSORS), + "[mirai:rps:scissors]".deserializeMiraiCode() + ) + assertEquals( + messageChainOf(RockPaperScissors.PAPER), + "[mirai:rps:paper]".deserializeMiraiCode() + ) } } \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt b/mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt index 5e4e952a8..ecd71ae48 100644 --- a/mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt @@ -71,6 +71,7 @@ internal class MessageSerializationTest : AbstractTest() { AtAll, image, Face(Face.AI_NI), + RockPaperScissors.PAPER, UnsupportedMessageImpl(ImMsgBody.Elem()) ) diff --git a/mirai-core/src/commonTest/kotlin/message/protocol/impl/MarketFaceProtocolTest.kt b/mirai-core/src/commonTest/kotlin/message/protocol/impl/MarketFaceProtocolTest.kt index c947c114e..260805ba9 100644 --- a/mirai-core/src/commonTest/kotlin/message/protocol/impl/MarketFaceProtocolTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/protocol/impl/MarketFaceProtocolTest.kt @@ -21,6 +21,7 @@ import net.mamoe.mirai.internal.testFramework.dynamicTest import net.mamoe.mirai.internal.testFramework.runDynamicTests import net.mamoe.mirai.message.data.Dice import net.mamoe.mirai.message.data.MarketFace +import net.mamoe.mirai.message.data.RockPaperScissors import net.mamoe.mirai.utils.hexToBytes import kotlin.test.BeforeTest import kotlin.test.Test @@ -104,6 +105,354 @@ internal class MarketFaceProtocolTest : AbstractMessageProtocolTest() { }.doEncoderChecks() } + @Test + fun `decode RockPaperScissors`() { + // region WinQQ PC + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + itemType = 6, + faceInfo = 1, + faceId = "E5 D8 89 F1 DF 79 B2 B4 51 83 F6 25 58 44 65 D3".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 100, + imageHeight = 100, + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + attr7Buf = "01".hexToBytes(), + ), + ), + ) + + message(RockPaperScissors.ROCK) + useOrdinaryEquality() + }.doDecoderChecks() + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + itemType = 6, + faceInfo = 1, + faceId = "62 8F A4 AB 7B 6C 2B CC FC DC D0 C2 DA F7 A6 0C".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 100, + imageHeight = 100, + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + attr7Buf = "01".hexToBytes(), + ), + ), + ) + + message(RockPaperScissors.SCISSORS) + useOrdinaryEquality() + }.doDecoderChecks() + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + itemType = 6, + faceInfo = 1, + faceId = "45 7C DE 42 0F 59 8E B4 24 CE D2 E9 05 D3 8D 8B".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 100, + imageHeight = 100, + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + attr7Buf = "01".hexToBytes(), + ), + ), + ) + + message(RockPaperScissors.PAPER) + useOrdinaryEquality() + }.doDecoderChecks() + // endregion + + // region AndroidQQ 8.4.18.49145 + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=2".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 32 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + ) + message(RockPaperScissors.PAPER) + useOrdinaryEquality() + }.doDecoderChecks() + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=0".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 30 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + ) + message(RockPaperScissors.ROCK) + useOrdinaryEquality() + }.doDecoderChecks() + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=1".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 31 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + ) + message(RockPaperScissors.SCISSORS) + useOrdinaryEquality() + }.doDecoderChecks() + // endregion + + // region MacOS + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=0".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 30 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + ) + + message(RockPaperScissors.ROCK) + useOrdinaryEquality() + }.doDecoderChecks() + // endregion + + // region iOS + buildCodingChecks { + elem( + // ROCK + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=0".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 30 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + ) + message(RockPaperScissors.ROCK) + useOrdinaryEquality() + }.doDecoderChecks() + buildCodingChecks { // paper + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=2".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 32 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + ) + message(RockPaperScissors.PAPER) + useOrdinaryEquality() + }.doDecoderChecks() + // endregion + } + + @Test + fun `encode RockPaperScissors`() { + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=0".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 30 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + extraInfo = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.ExtraInfo( + flags = 8, + groupMask = 1, + ), + ), + ) + message(RockPaperScissors.ROCK) + }.doBothChecks() + + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=1".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 31 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + extraInfo = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.ExtraInfo( + flags = 8, + groupMask = 1, + ), + ), + ) + message(RockPaperScissors.SCISSORS) + }.doBothChecks() + + buildCodingChecks { + elem( + net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + marketFace = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MarketFace( + faceName = "[猜拳]".toByteArray(), /* 5B E7 8C 9C E6 8B B3 5D */ + itemType = 6, + faceInfo = 1, + faceId = "83 C8 A2 93 AE 65 CA 14 0F 34 81 20 A7 74 48 EE".hexToBytes(), + tabId = 11415, + subType = 3, + key = "7de39febcf45e6db".toByteArray(), /* 37 64 65 33 39 66 65 62 63 66 34 35 65 36 64 62 */ + imageWidth = 200, + imageHeight = 200, + mobileParam = "rscType?1;value=2".toByteArray(), /* 72 73 63 54 79 70 65 3F 31 3B 76 61 6C 75 65 3D 32 */ + pbReserve = "0A 06 08 C8 01 10 C8 01 40 01".hexToBytes(), + ), + ), net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + text = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Text( + str = "[猜拳]", + ), + ), net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem( + extraInfo = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.ExtraInfo( + flags = 8, + groupMask = 1, + ), + ) + ) + message(RockPaperScissors.PAPER) + }.doBothChecks() + + } @Test fun `encode decode MarketFace from Android`() {