mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-03 02:29:21 +08:00
Mirai code (#768)
* Mirai Code * cleanup code * mirai code of MarketFace
This commit is contained in:
parent
da7abc5bf6
commit
2f903cef9e
@ -10,6 +10,7 @@
|
||||
package net.mamoe.mirai.message.code
|
||||
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
|
||||
|
||||
/**
|
||||
@ -36,5 +37,9 @@ public interface CodableMessage : Message {
|
||||
*
|
||||
* @suppress 警告: 此 API 可能在任何时刻被改变
|
||||
*/
|
||||
public fun toMiraiCode(): String = this.toString()
|
||||
public fun toMiraiCode(): String = buildString { appendMiraiCode(this) }
|
||||
|
||||
// Using StringBuilder faster than direct plus objects
|
||||
@MiraiExperimentalApi
|
||||
public fun appendMiraiCode(builder: StringBuilder)
|
||||
}
|
@ -12,11 +12,21 @@
|
||||
|
||||
package net.mamoe.mirai.message.code
|
||||
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.message.code.internal.parseMiraiCodeImpl
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.utils.safeCast
|
||||
|
||||
/**
|
||||
* 解析形如 "[mirai:]" 的 mirai 码, 即 [Message.toString] 返回的内容.
|
||||
*/
|
||||
public fun String.parseMiraiCode(): MessageChain = parseMiraiCodeImpl()
|
||||
@JvmOverloads
|
||||
public fun String.parseMiraiCode(contact: Contact? = null): MessageChain = parseMiraiCodeImpl(contact)
|
||||
|
||||
public fun <T : Message> Iterable<T>.toMiraiCode(): String = iterator().toMiraiCode()
|
||||
public fun <T : Message> Iterator<T>.toMiraiCode(): String = buildString {
|
||||
this@toMiraiCode.forEach {
|
||||
it.safeCast<CodableMessage>()?.appendMiraiCode(this)
|
||||
}
|
||||
}
|
||||
|
@ -11,55 +11,95 @@
|
||||
|
||||
package net.mamoe.mirai.message.code.internal
|
||||
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
|
||||
|
||||
@Suppress("RegExpRedundantEscape") // required on android
|
||||
internal val codeRegex = Regex("""(?:\[mirai:([^\]]*)?:(.*?)?\])|(?:\[mirai:([^:]+)\])""")
|
||||
|
||||
internal fun String.parseMiraiCodeImpl(): MessageChain = buildMessageChain {
|
||||
internal fun String.parseMiraiCodeImpl(contact: Contact?): MessageChain = buildMessageChain {
|
||||
forEachMiraiCode { origin, name, args ->
|
||||
if (name == null) {
|
||||
add(PlainText(origin))
|
||||
add(PlainText(origin.decodeMiraiCode()))
|
||||
return@forEachMiraiCode
|
||||
}
|
||||
val parser = MiraiCodeParsers[name] ?: kotlin.run {
|
||||
add(PlainText(origin))
|
||||
add(PlainText(origin.decodeMiraiCode()))
|
||||
return@forEachMiraiCode
|
||||
}
|
||||
parser.argsRegex.matchEntire(args)
|
||||
?.destructured
|
||||
?.let {
|
||||
parser.runCatching {
|
||||
mapper(it)
|
||||
contact.mapper(it)
|
||||
}.getOrNull()
|
||||
}
|
||||
?.let(::add)
|
||||
?: add(PlainText(origin))
|
||||
?: add(PlainText(origin.decodeMiraiCode()))
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun String.forEachMiraiCode(crossinline block: (origin: String, name: String?, args: String) -> Unit) {
|
||||
var lastIndex = 0
|
||||
for (result in codeRegex.findAll(this)) {
|
||||
if (result.range.first != lastIndex) {
|
||||
// skipped string
|
||||
block(substring(lastIndex, result.range.first), null, "")
|
||||
internal fun String.forEachMiraiCode(block: (origin: String, name: String?, args: String) -> Unit) {
|
||||
var pos = 0
|
||||
var lastPos = 0
|
||||
val len = length - 7 // [mirai:
|
||||
fun findEnding(start: Int): Int {
|
||||
var pos0 = start
|
||||
while (pos0 < length) {
|
||||
when (get(pos0)) {
|
||||
'\\' -> pos0 += 2
|
||||
']' -> return pos0
|
||||
else -> pos0++
|
||||
}
|
||||
}
|
||||
|
||||
lastIndex = result.range.last + 1
|
||||
if (result.groups[3] != null) {
|
||||
// no param
|
||||
block(result.value, result.groups[3]!!.value, "")
|
||||
} else block(result.value, result.groups[1]!!.value, result.groups[2]?.value ?: "")
|
||||
return -1
|
||||
}
|
||||
if (lastIndex != this.length) {
|
||||
block(substring(lastIndex, this.length), null, "")
|
||||
while (pos < len) {
|
||||
when (get(pos)) {
|
||||
'\\' -> {
|
||||
pos += 2
|
||||
}
|
||||
'[' -> {
|
||||
if (get(pos + 1) == 'm' && get(pos + 2) == 'i' &&
|
||||
get(pos + 3) == 'r' && get(pos + 4) == 'a' &&
|
||||
get(pos + 5) == 'i' && get(pos + 6) == ':'
|
||||
) {
|
||||
val begin = pos
|
||||
pos += 7
|
||||
val ending = findEnding(pos)
|
||||
if (ending == -1) {
|
||||
block(substring(lastPos), null, "")
|
||||
return
|
||||
} else {
|
||||
if (lastPos < begin) {
|
||||
block(substring(lastPos, begin), null, "")
|
||||
}
|
||||
val v = substring(begin, ending + 1)
|
||||
val splitter = v.indexOf(':', 7)
|
||||
block(
|
||||
v, if (splitter == -1)
|
||||
v.substring(7, v.length - 1)
|
||||
else v.substring(7, splitter),
|
||||
if (splitter == -1) {
|
||||
""
|
||||
} else v.substring(splitter + 1, v.length - 1)
|
||||
)
|
||||
lastPos = ending + 1
|
||||
pos = lastPos
|
||||
}
|
||||
} else pos++
|
||||
}
|
||||
else -> {
|
||||
pos++
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastPos < length) {
|
||||
block(substring(lastPos), null, "")
|
||||
}
|
||||
}
|
||||
|
||||
internal object MiraiCodeParsers : Map<String, MiraiCodeParser> by mapOf(
|
||||
"at" to MiraiCodeParser(Regex("""(\d*)""")) { (target, _) ->
|
||||
"at" to MiraiCodeParser(Regex("""(\d*)""")) { (target) ->
|
||||
At(target.toLong())
|
||||
},
|
||||
"atall" to MiraiCodeParser(Regex("")) {
|
||||
@ -79,40 +119,44 @@ internal object MiraiCodeParsers : Map<String, MiraiCodeParser> by mapOf(
|
||||
},
|
||||
"flash" to MiraiCodeParser(Regex("""(.*)""")) { (id) ->
|
||||
Image(id).flash()
|
||||
},
|
||||
"service" to MiraiCodeParser(Regex("""(\d*),(.*)""")) { (id, content) ->
|
||||
SimpleServiceMessage(id.toInt(), content.decodeMiraiCode())
|
||||
},
|
||||
"app" to MiraiCodeParser(Regex("""(.*)""")) { (content) ->
|
||||
LightApp(content.decodeMiraiCode())
|
||||
}
|
||||
)
|
||||
|
||||
/*
|
||||
internal object MiraiCodeParsers2 : Map<String, (args: String) -> Message?> by mapOf(
|
||||
"at" to l@{ args ->
|
||||
val group = args.split(',')
|
||||
if (group.size != 2) return@l null
|
||||
val target = group[0].toLongOrNull() ?: return@l null
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
At(target, group[1])
|
||||
},
|
||||
"atall" to l@{
|
||||
AtAll
|
||||
},
|
||||
"poke" to l@{ args ->
|
||||
val group = args.split(',')
|
||||
if (group.size != 2) return@l null
|
||||
val type = group[1].toIntOrNull() ?: return@l null
|
||||
val id = group[2].toIntOrNull() ?: return@l null
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
PokeMessage(group[0], type, id)
|
||||
},
|
||||
"vipface" to l@{ args ->
|
||||
val group = args.split(',')
|
||||
if (group.size != 2) return@l null
|
||||
val type = group[1].toIntOrNull() ?: return@l null
|
||||
val id = group[2].toIntOrNull() ?: return@l null
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
PokeMessage(group[0], type, id)
|
||||
}
|
||||
)*/
|
||||
|
||||
internal class MiraiCodeParser(
|
||||
val argsRegex: Regex,
|
||||
val mapper: MiraiCodeParser.(MatchResult.Destructured) -> Message?
|
||||
)
|
||||
val mapper: Contact?.(MatchResult.Destructured) -> Message?
|
||||
)
|
||||
|
||||
@MiraiInternalApi
|
||||
public fun StringBuilder.appendAsMiraiCode(value: String): StringBuilder = apply {
|
||||
value.forEach { char ->
|
||||
when (char) {
|
||||
'[', ']',
|
||||
':', ',',
|
||||
'\\',
|
||||
-> append("\\").append(char)
|
||||
'\n' -> append("\\n")
|
||||
'\r' -> append("\\r")
|
||||
else -> append(char)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("RegExpRedundantEscape")
|
||||
internal val DECODE_MIRAI_CODE_REGEX = """\\.""".toRegex()
|
||||
internal val DECODE_MIRAI_CODE_TRANSLATOR: (MatchResult) -> String = {
|
||||
when (it.value[1]) {
|
||||
'n' -> "\n"
|
||||
'r' -> "\r"
|
||||
'\n' -> ""
|
||||
else -> it.value.substring(1)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun String.decodeMiraiCode() = replace(DECODE_MIRAI_CODE_REGEX, DECODE_MIRAI_CODE_TRANSLATOR)
|
||||
|
@ -55,6 +55,10 @@ public data class At(
|
||||
return "@${member.nameCardOrNick}"
|
||||
}
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:at:").append(target).append(']')
|
||||
}
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* 构造一个 [At], 仅供内部使用, 否则可能造成消息无法发出的问题.
|
||||
|
@ -40,6 +40,14 @@ public object AtAll :
|
||||
return other === this
|
||||
}
|
||||
|
||||
override fun toMiraiCode(): String {
|
||||
return toString()
|
||||
}
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append(toString())
|
||||
}
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
return display.hashCode()
|
||||
}
|
||||
|
@ -29,6 +29,10 @@ public data class Face(public val id: Int) : // used in delegation
|
||||
public val name: String get() = contentToString().let { it.substring(1, it.length - 1) }
|
||||
public override fun contentToString(): String = names.getOrElse(id) { "[表情]" }
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:face:").append(id).append(']')
|
||||
}
|
||||
|
||||
public override fun equals(other: Any?): Boolean = other is Face && other.id == this.id
|
||||
public override fun hashCode(): Int = id
|
||||
|
||||
|
@ -16,6 +16,7 @@ package net.mamoe.mirai.message.data
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
import net.mamoe.mirai.message.data.VipFace.Kind
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
import net.mamoe.mirai.utils.PlannedRemoval
|
||||
@ -173,6 +174,12 @@ public data class PokeMessage @MiraiInternalApi constructor(
|
||||
|
||||
private val stringValue = "[mirai:poke:$name,$pokeType,$id]"
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:poke:").appendAsMiraiCode(name)
|
||||
.append(',').append(pokeType).append(',').append(id)
|
||||
.append(']')
|
||||
}
|
||||
|
||||
override fun toString(): String = stringValue
|
||||
override fun contentToString(): String = "[戳一戳]"
|
||||
//businessType=0x00000001(1)
|
||||
@ -290,6 +297,9 @@ public data class VipFace @MiraiInternalApi constructor(
|
||||
private infix fun Int.to(name: String): Kind = Kind(this, name)
|
||||
}
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append(stringValue) // TODO:
|
||||
}
|
||||
|
||||
private val stringValue = "[mirai:vipface:$kind,$count]"
|
||||
|
||||
@ -339,6 +349,11 @@ public data class FlashImage(
|
||||
|
||||
private val stringValue: String by lazy(LazyThreadSafetyMode.NONE) { "[mirai:flash:${image.imageId}]" }
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append(stringValue)
|
||||
}
|
||||
|
||||
override fun toMiraiCode(): String = stringValue
|
||||
public override fun toString(): String = stringValue
|
||||
public override fun contentToString(): String = "[闪照]"
|
||||
}
|
||||
|
@ -229,6 +229,9 @@ public sealed class AbstractImage : Image {
|
||||
|
||||
final override fun toString(): String = _stringValue!!
|
||||
final override fun contentToString(): String = "[图片]"
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:image:").append(imageId).append("]")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,8 +20,10 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.quote
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.recall
|
||||
import net.mamoe.mirai.utils.safeCast
|
||||
import kotlin.js.JsName
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@ -56,7 +58,7 @@ import kotlin.reflect.KProperty
|
||||
*/
|
||||
@Serializable(MessageChain.Serializer::class)
|
||||
@Suppress("FunctionName", "DeprecatedCallableAddReplaceWith", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
public interface MessageChain : Message, List<SingleMessage>, RandomAccess {
|
||||
public interface MessageChain : Message, List<SingleMessage>, RandomAccess, CodableMessage {
|
||||
/**
|
||||
* 元素数量. [EmptyMessageChain] 不参加计数.
|
||||
*/
|
||||
@ -98,6 +100,10 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess {
|
||||
override fun deserialize(decoder: Decoder): MessageChain = delegate.deserialize(decoder).asMessageChain()
|
||||
override fun serialize(encoder: Encoder, value: MessageChain): Unit = delegate.serialize(encoder, value)
|
||||
}
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
forEach { it.safeCast<CodableMessage>()?.appendMiraiCode(builder) }
|
||||
}
|
||||
}
|
||||
|
||||
// region accessors
|
||||
@ -430,4 +436,6 @@ public object EmptyMessageChain : MessageChain, Iterator<SingleMessage>, List<Si
|
||||
public override fun iterator(): Iterator<SingleMessage> = this
|
||||
public override fun hasNext(): Boolean = false
|
||||
public override fun next(): SingleMessage = throw NoSuchElementException("EmptyMessageChain is empty.")
|
||||
override fun toMiraiCode(): String = ""
|
||||
override fun appendMiraiCode(builder: StringBuilder) {}
|
||||
}
|
@ -14,6 +14,8 @@
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
|
||||
/**
|
||||
* 纯文本. 可含 emoji 表情如 😊.
|
||||
@ -23,13 +25,17 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
public data class PlainText(
|
||||
public val content: String
|
||||
) : MessageContent {
|
||||
) : MessageContent, CodableMessage {
|
||||
@Suppress("unused")
|
||||
public constructor(charSequence: CharSequence) : this(charSequence.toString())
|
||||
|
||||
public override fun toString(): String = content
|
||||
public override fun contentToString(): String = content
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.appendAsMiraiCode(content)
|
||||
}
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.PlannedRemoval
|
||||
import net.mamoe.mirai.utils.safeCast
|
||||
@ -94,10 +96,14 @@ public interface RichMessage : MessageContent, ConstrainSingle {
|
||||
* @see ServiceMessage 服务消息
|
||||
*/
|
||||
@Serializable
|
||||
public data class LightApp(override val content: String) : RichMessage {
|
||||
public data class LightApp(override val content: String) : RichMessage, CodableMessage {
|
||||
public companion object Key : AbstractMessageKey<LightApp>({ it.safeCast() })
|
||||
|
||||
public override fun toString(): String = "[mirai:app:$content]"
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:app:").appendAsMiraiCode(content).append(']')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,6 +136,7 @@ public class SimpleServiceMessage(
|
||||
result = 31 * result + content.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -141,7 +148,7 @@ public class SimpleServiceMessage(
|
||||
* @see LightApp 小程序类型消息
|
||||
* @see SimpleServiceMessage
|
||||
*/
|
||||
public interface ServiceMessage : RichMessage {
|
||||
public interface ServiceMessage : RichMessage, CodableMessage {
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<RichMessage, ServiceMessage>(RichMessage, { it.safeCast() })
|
||||
|
||||
@ -149,6 +156,10 @@ public interface ServiceMessage : RichMessage {
|
||||
* 目前未知, XML 一般为 60, JSON 一般为 1
|
||||
*/
|
||||
public val serviceId: Int
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:service:").append(serviceId).append(',').appendAsMiraiCode(content).append(']')
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.message.code
|
||||
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TestMiraiCode {
|
||||
@Test
|
||||
fun testCodes() {
|
||||
assertEquals(AtAll.asMessageChain(), "[mirai:atall]".parseMiraiCode())
|
||||
assertEquals(PlainText("[Hello").asMessageChain(), "\\[Hello".parseMiraiCode())
|
||||
assertEquals(buildMessageChain {
|
||||
+PlainText("1")
|
||||
+AtAll
|
||||
+PlainText("2345")
|
||||
+AtAll
|
||||
}, "1[mirai:atall]2345[mirai:atall]".parseMiraiCode())
|
||||
assertEquals(buildMessageChain {
|
||||
+PlainText("1")
|
||||
+AtAll
|
||||
+PlainText("2345[mirai:atall")
|
||||
}, "1[mirai:atall]2345[mirai:atall".parseMiraiCode())
|
||||
assertEquals(buildMessageChain {
|
||||
+PlainText("[mirai:atall]")
|
||||
}, "\\[mirai:atall]".parseMiraiCode())
|
||||
assertEquals(buildMessageChain {
|
||||
+PlainText("[mirai:atall]")
|
||||
}, "[mirai:atall\\]".parseMiraiCode())
|
||||
assertEquals(buildMessageChain {
|
||||
+PlainText("[mirai:atall]")
|
||||
}, "[mirai\\:atall]".parseMiraiCode())
|
||||
assertEquals(buildMessageChain {
|
||||
+SimpleServiceMessage(1, "[HiHi!!!\\]")
|
||||
+PlainText(" XE")
|
||||
}, "[mirai:service:1,\\[HiHi!!!\\\\\\]] XE".parseMiraiCode())
|
||||
}
|
||||
}
|
@ -17,8 +17,10 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.utils.hexToBytes
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.toByteArray
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
import net.mamoe.mirai.message.data.Face
|
||||
import net.mamoe.mirai.message.data.MarketFace
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
|
||||
internal val FACE_BUF = "00 01 00 04 52 CC F5 D0".hexToBytes()
|
||||
|
||||
@ -51,5 +53,11 @@ internal data class MarketFaceImpl internal constructor(
|
||||
override val name: String = delegate.faceName.decodeToString()
|
||||
@Transient
|
||||
override val id: Int = delegate.tabId
|
||||
|
||||
@MiraiExperimentalApi
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:marketface:").append(id).append(",").appendAsMiraiCode(name).append(']')
|
||||
}
|
||||
|
||||
override fun toString() = "[mirai:marketface:$id,$name]"
|
||||
}
|
@ -121,6 +121,10 @@ internal abstract class AbstractImage : Image { // make sealed in 1.3.0 ?
|
||||
|
||||
final override fun toString(): String = _stringValue!!
|
||||
final override fun contentToString(): String = "[图片]"
|
||||
|
||||
override fun appendMiraiCode(builder: StringBuilder) {
|
||||
builder.append("[mirai:image:").append(imageId).append("]")
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ConstOriginUrlAware : Image {
|
||||
|
Loading…
Reference in New Issue
Block a user