[core] feat: RockPaperScissors (#2220)

* [core] feat: RockPaperScissors

Co-authored-by: Karlatemp <kar@kasukusakura.com>

* docs update

* rename `eliminate` to `eliminates`

Co-authored-by: Karlatemp <kar@kasukusakura.com>
This commit is contained in:
cssxsh 2023-01-03 10:00:32 +08:00 committed by GitHub
parent eea2ef509d
commit 2cffb7a4a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 626 additions and 1 deletions

View File

@ -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` 实例

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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,
)
}
}

View File

@ -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)
}

View File

@ -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(

View File

@ -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)
)
}
}
}

View File

@ -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()
)
}
}

View File

@ -71,6 +71,7 @@ internal class MessageSerializationTest : AbstractTest() {
AtAll,
image,
Face(Face.AI_NI),
RockPaperScissors.PAPER,
UnsupportedMessageImpl(ImMsgBody.Elem())
)

View File

@ -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`() {