Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
1b4e1475
Commit
1b4e1475
authored
Apr 23, 2020
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support ForwardMessage DSL
parent
6734403f
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
618 additions
and
55 deletions
+618
-55
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
...n/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
+30
-17
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
...ain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
+26
-4
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt
...n/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt
+13
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MultiMsg.kt
...e/mirai/qqandroid/network/protocol/data/proto/MultiMsg.kt
+11
-11
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/MultiMsg.kt
.../mirai/qqandroid/network/protocol/packet/chat/MultiMsg.kt
+8
-8
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/ForwardMessage.kt
...ain/kotlin/net.mamoe.mirai/message/data/ForwardMessage.kt
+525
-14
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
...commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
+1
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/RichMessage.kt
...onMain/kotlin/net.mamoe.mirai/message/data/RichMessage.kt
+4
-1
No files found.
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
View file @
1b4e1475
...
@@ -552,12 +552,14 @@ internal abstract class QQAndroidBotBase constructor(
...
@@ -552,12 +552,14 @@ internal abstract class QQAndroidBotBase constructor(
@MiraiExperimentalAPI
@MiraiExperimentalAPI
internal
suspend
fun
lowLevelSendGroupLongOrForwardMessage
(
internal
suspend
fun
lowLevelSendGroupLongOrForwardMessage
(
groupCode
:
Long
,
groupCode
:
Long
,
message
:
Collection
<
MessageChain
>,
message
:
Collection
<
ForwardMessage
.
INode
>,
isLong
:
Boolean
isLong
:
Boolean
,
forwardMessage
:
ForwardMessage
?
):
MessageReceipt
<
Group
>
{
):
MessageReceipt
<
Group
>
{
message
.
forEach
{
message
.
forEach
{
it
.
firstIsInstanceOrNull
<
QuoteReply
>()
?.
source
?
.
ensureSequenceIdAvailable
()
it
.
message
.
ensureSequenceIdAvailable
()
}
}
val
group
=
getGroup
(
groupCode
)
val
group
=
getGroup
(
groupCode
)
val
time
=
currentTimeSeconds
val
time
=
currentTimeSeconds
...
@@ -566,10 +568,8 @@ internal abstract class QQAndroidBotBase constructor(
...
@@ -566,10 +568,8 @@ internal abstract class QQAndroidBotBase constructor(
network
.
run
{
network
.
run
{
val
data
=
message
.
calculateValidationDataForGroup
(
val
data
=
message
.
calculateValidationDataForGroup
(
sequenceId
=
sequenceId
,
sequenceId
=
sequenceId
,
time
=
time
.
toInt
(),
random
=
Random
.
nextInt
().
absoluteValue
.
toUInt
(),
random
=
Random
.
nextInt
().
absoluteValue
.
toUInt
(),
groupCode
=
groupCode
,
groupCode
=
groupCode
,
botId
=
this
@QQAndroidBotBase
.
id
,
botMemberNameCard
=
group
.
botAsMember
.
nameCardOrNick
botMemberNameCard
=
group
.
botAsMember
.
nameCardOrNick
)
)
...
@@ -646,21 +646,30 @@ internal abstract class QQAndroidBotBase constructor(
...
@@ -646,21 +646,30 @@ internal abstract class QQAndroidBotBase constructor(
return
if
(
isLong
)
{
return
if
(
isLong
)
{
group
.
sendMessage
(
group
.
sendMessage
(
RichMessage
.
longMessage
(
RichMessage
.
longMessage
(
brief
=
message
.
joinToString
(
limit
=
27
)
{
it
.
contentToString
()
},
brief
=
message
.
joinToString
(
limit
=
27
)
{
it
.
message
.
contentToString
()
},
resId
=
resId
,
resId
=
resId
,
timeSeconds
=
time
timeSeconds
=
time
)
)
)
)
}
else
{
}
else
{
checkNotNull
(
forwardMessage
)
{
"Internal error: forwardMessage is null when sending forward"
}
group
.
sendMessage
(
group
.
sendMessage
(
RichMessage
.
forwardMessage
(
RichMessage
.
forwardMessage
(
resId
=
resId
,
resId
=
resId
,
timeSeconds
=
time
,
timeSeconds
=
time
,
preview
=
message
.
take
(
3
).
joinToString
{
// preview = message.take(5).joinToString {
"""
// """
<title size="26" color="#777777" maxLines="2" lineSpace="12">${it.joinToString(limit = 10)}</title>
// <title size="26" color="#777777" maxLines="2" lineSpace="12">${it.message.asMessageChain().joinToString(limit = 10)}</title>
"""
.
trimIndent
()
// """.trimIndent()
}
// },
preview
=
forwardMessage
.
displayStrategy
.
generatePreview
(
forwardMessage
).
take
(
4
)
.
map
{
"""<title size="26" color="#777777" maxLines="2" lineSpace="12">$it</title>"""
}.
joinToString
(
""
),
title
=
forwardMessage
.
displayStrategy
.
generateTitle
(
forwardMessage
),
brief
=
forwardMessage
.
displayStrategy
.
generateBrief
(
forwardMessage
),
source
=
forwardMessage
.
displayStrategy
.
generateSource
(
forwardMessage
),
summary
=
forwardMessage
.
displayStrategy
.
generateSummary
(
forwardMessage
)
)
)
)
)
}
}
...
@@ -769,21 +778,25 @@ private fun RichMessage.Templates.longMessage(brief: String, resId: String, time
...
@@ -769,21 +778,25 @@ private fun RichMessage.Templates.longMessage(brief: String, resId: String, time
private
fun
RichMessage
.
Templates
.
forwardMessage
(
private
fun
RichMessage
.
Templates
.
forwardMessage
(
resId
:
String
,
resId
:
String
,
timeSeconds
:
Long
,
timeSeconds
:
Long
,
preview
:
String
preview
:
String
,
title
:
String
,
brief
:
String
,
source
:
String
,
summary
:
String
):
ForwardMessageInternal
{
):
ForwardMessageInternal
{
val
template
=
"""
val
template
=
"""
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<msg serviceID="35" templateID="1" action="viewMultiMsg" brief="
[聊天记录]
"
<msg serviceID="35" templateID="1" action="viewMultiMsg" brief="
$brief
"
m_resid="$resId" m_fileName="$timeSeconds"
m_resid="$resId" m_fileName="$timeSeconds"
tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0">
tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0">
<item layout="1" advertiser_id="0" aid="0">
<item layout="1" advertiser_id="0" aid="0">
<title size="34" maxLines="2" lineSpace="12">
群聊的聊天记录
</title>
<title size="34" maxLines="2" lineSpace="12">
$title
</title>
$preview
$preview
<hr hidden="false" style="0"/>
<hr hidden="false" style="0"/>
<summary size="26" color="#777777">
查看3条转发消息
</summary>
<summary size="26" color="#777777">
$summary
</summary>
</item>
</item>
<source name="
聊天记录
" icon="" action="" appid="-1"/>
<source name="
$source
" icon="" action="" appid="-1"/>
</msg>
</msg>
"""
.
trimIndent
()
"""
.
trimIndent
()
.
replace
(
"\n"
,
" "
)
return
ForwardMessageInternal
(
template
)
return
ForwardMessageInternal
(
template
)
}
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
View file @
1b4e1475
...
@@ -295,7 +295,13 @@ internal class GroupImpl(
...
@@ -295,7 +295,13 @@ internal class GroupImpl(
}
}
}
}
if
(
message
is
ForwardMessage
)
{
if
(
message
is
ForwardMessage
)
{
return
bot
.
lowLevelSendGroupLongOrForwardMessage
(
this
.
id
,
message
.
messageList
,
false
)
check
(
message
.
nodeList
.
size
<
200
)
{
throw
MessageTooLargeException
(
this
,
message
,
message
,
"ForwardMessage allows up to 200 nodes, but found ${message.nodeList.size}"
)
}
return
bot
.
lowLevelSendGroupLongOrForwardMessage
(
this
.
id
,
message
.
nodeList
,
false
,
message
)
}
}
val
msg
:
MessageChain
val
msg
:
MessageChain
...
@@ -321,8 +327,16 @@ internal class GroupImpl(
...
@@ -321,8 +327,16 @@ internal class GroupImpl(
)
)
}
}
if
(
length
>
702
||
imageCnt
>
2
)
if
(
length
>
702
||
imageCnt
>
2
)
{
return
bot
.
lowLevelSendGroupLongOrForwardMessage
(
this
.
id
,
listOf
(
event
.
message
),
true
)
return
bot
.
lowLevelSendGroupLongOrForwardMessage
(
this
.
id
,
listOf
(
ForwardMessage
.
Node
(
senderId
=
bot
.
id
,
time
=
currentTimeSeconds
.
toInt
(),
message
=
event
.
message
,
senderName
=
bot
.
nick
)
),
true
,
null
)
}
msg
=
event
.
message
msg
=
event
.
message
}
else
msg
=
message
.
asMessageChain
()
}
else
msg
=
message
.
asMessageChain
()
...
@@ -343,7 +357,15 @@ internal class GroupImpl(
...
@@ -343,7 +357,15 @@ internal class GroupImpl(
120
->
throw
BotIsBeingMutedException
(
this
@GroupImpl
)
120
->
throw
BotIsBeingMutedException
(
this
@GroupImpl
)
34
->
{
34
->
{
kotlin
.
runCatching
{
// allow retry once
kotlin
.
runCatching
{
// allow retry once
return
bot
.
lowLevelSendGroupLongOrForwardMessage
(
id
,
listOf
(
msg
),
true
)
return
bot
.
lowLevelSendGroupLongOrForwardMessage
(
id
,
listOf
(
ForwardMessage
.
Node
(
senderId
=
bot
.
id
,
time
=
currentTimeSeconds
.
toInt
(),
message
=
msg
,
senderName
=
bot
.
nick
)
),
true
,
null
)
}.
getOrElse
{
}.
getOrElse
{
throw
IllegalStateException
(
"internal error: send message failed(34)"
,
it
)
throw
IllegalStateException
(
"internal error: send message failed(34)"
,
it
)
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt
View file @
1b4e1475
...
@@ -15,6 +15,7 @@ import net.mamoe.mirai.Bot
...
@@ -15,6 +15,7 @@ import net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.Friend
import
net.mamoe.mirai.contact.Friend
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.event.internal.MiraiAtomicBoolean
import
net.mamoe.mirai.event.internal.MiraiAtomicBoolean
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.OnlineMessageSource
import
net.mamoe.mirai.message.data.OnlineMessageSource
...
@@ -47,6 +48,18 @@ internal suspend inline fun MessageSource.ensureSequenceIdAvailable() {
...
@@ -47,6 +48,18 @@ internal suspend inline fun MessageSource.ensureSequenceIdAvailable() {
}*/
}*/
}
}
@Suppress
(
"RedundantSuspendModifier"
,
"unused"
)
internal
suspend
inline
fun
Message
.
ensureSequenceIdAvailable
()
{
// no suspend.
// obsolete but keep for future
return
/*
if (this is MessageSourceToGroupImpl) {
this.ensureSequenceIdAvailable()
}*/
}
internal
class
MessageSourceFromFriendImpl
(
internal
class
MessageSourceFromFriendImpl
(
override
val
bot
:
Bot
,
override
val
bot
:
Bot
,
val
msg
:
MsgComm
.
Msg
val
msg
:
MsgComm
.
Msg
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MultiMsg.kt
View file @
1b4e1475
...
@@ -9,32 +9,32 @@ import kotlin.jvm.JvmField
...
@@ -9,32 +9,32 @@ import kotlin.jvm.JvmField
@Serializable
@Serializable
internal
class
MultiMsg
:
ProtoBuf
{
internal
class
MultiMsg
:
ProtoBuf
{
@Serializable
@Serializable
internal
class
ExternMsg
(
internal
class
ExternMsg
(
@ProtoId
(
1
)
@JvmField
val
channelType
:
Int
=
0
@ProtoId
(
1
)
@JvmField
val
channelType
:
Int
=
0
)
:
ProtoBuf
)
:
ProtoBuf
@Serializable
@Serializable
internal
class
MultiMsgApplyDownReq
(
internal
class
MultiMsgApplyDownReq
(
@ProtoId
(
1
)
@JvmField
val
msgResid
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
1
)
@JvmField
val
msgResid
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
2
)
@JvmField
val
msgType
:
Int
=
0
,
@ProtoId
(
2
)
@JvmField
val
msgType
:
Int
=
0
,
@ProtoId
(
3
)
@JvmField
val
srcUin
:
Long
=
0L
@ProtoId
(
3
)
@JvmField
val
srcUin
:
Long
=
0L
)
:
ProtoBuf
)
:
ProtoBuf
@Serializable
@Serializable
internal
class
MultiMsgApplyDownRsp
(
internal
class
MultiMsgApplyDownRsp
(
@ProtoId
(
1
)
@JvmField
val
result
:
Int
=
0
,
@ProtoId
(
1
)
@JvmField
val
result
:
Int
=
0
,
@ProtoId
(
2
)
@JvmField
val
thumbDownPara
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
2
)
@JvmField
val
thumbDownPara
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
3
)
@JvmField
val
msgKey
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
3
)
@JvmField
val
msgKey
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
4
)
@JvmField
val
uint32DownIp
:
List
<
Int
>?
=
null
,
@ProtoId
(
4
)
@JvmField
val
uint32DownIp
:
List
<
Int
>?
=
null
,
@ProtoId
(
5
)
@JvmField
val
uint32DownPort
:
List
<
Int
>?
=
null
,
@ProtoId
(
5
)
@JvmField
val
uint32DownPort
:
List
<
Int
>?
=
null
,
@ProtoId
(
6
)
@JvmField
val
msgResid
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
6
)
@JvmField
val
msgResid
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
7
)
@JvmField
val
msgExternInfo
:
MultiMsg
.
ExternMsg
?
=
null
,
@ProtoId
(
7
)
@JvmField
val
msgExternInfo
:
ExternMsg
?
=
null
,
@ProtoId
(
8
)
@JvmField
val
bytesDownIpV6
:
List
<
ByteArray
>?
=
null
,
@ProtoId
(
8
)
@JvmField
val
bytesDownIpV6
:
List
<
ByteArray
>?
=
null
,
@ProtoId
(
9
)
@JvmField
val
uint32DownV6Port
:
List
<
Int
>?
=
null
@ProtoId
(
9
)
@JvmField
val
uint32DownV6Port
:
List
<
Int
>?
=
null
)
:
ProtoBuf
)
:
ProtoBuf
@Serializable
@Serializable
internal
class
MultiMsgApplyUpReq
(
internal
class
MultiMsgApplyUpReq
(
@ProtoId
(
1
)
@JvmField
val
dstUin
:
Long
=
0L
,
@ProtoId
(
1
)
@JvmField
val
dstUin
:
Long
=
0L
,
@ProtoId
(
2
)
@JvmField
val
msgSize
:
Long
=
0L
,
@ProtoId
(
2
)
@JvmField
val
msgSize
:
Long
=
0L
,
@ProtoId
(
3
)
@JvmField
val
msgMd5
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
3
)
@JvmField
val
msgMd5
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
...
@@ -43,24 +43,24 @@ internal class MultiMsgApplyUpReq(
...
@@ -43,24 +43,24 @@ internal class MultiMsgApplyUpReq(
)
:
ProtoBuf
)
:
ProtoBuf
@Serializable
@Serializable
internal
class
MultiMsgApplyUpRsp
(
internal
class
MultiMsgApplyUpRsp
(
@ProtoId
(
1
)
@JvmField
val
result
:
Int
=
0
,
@ProtoId
(
1
)
@JvmField
val
result
:
Int
=
0
,
@ProtoId
(
2
)
@JvmField
val
msgResid
:
String
=
""
,
@ProtoId
(
2
)
@JvmField
val
msgResid
:
String
=
""
,
@ProtoId
(
3
)
@JvmField
val
msgUkey
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
3
)
@JvmField
val
msgUkey
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
4
)
@JvmField
val
uint32UpIp
:
List
<
Int
>,
@ProtoId
(
4
)
@JvmField
val
uint32UpIp
:
List
<
Int
>
=
listOf
()
,
@ProtoId
(
5
)
@JvmField
val
uint32UpPort
:
List
<
Int
>,
@ProtoId
(
5
)
@JvmField
val
uint32UpPort
:
List
<
Int
>
=
listOf
()
,
@ProtoId
(
6
)
@JvmField
val
blockSize
:
Long
=
0L
,
@ProtoId
(
6
)
@JvmField
val
blockSize
:
Long
=
0L
,
@ProtoId
(
7
)
@JvmField
val
upOffset
:
Long
=
0L
,
@ProtoId
(
7
)
@JvmField
val
upOffset
:
Long
=
0L
,
@ProtoId
(
8
)
@JvmField
val
applyId
:
Int
=
0
,
@ProtoId
(
8
)
@JvmField
val
applyId
:
Int
=
0
,
@ProtoId
(
9
)
@JvmField
val
msgKey
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
9
)
@JvmField
val
msgKey
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
10
)
@JvmField
val
msgSig
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
10
)
@JvmField
val
msgSig
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@ProtoId
(
11
)
@JvmField
val
msgExternInfo
:
MultiMsg
.
ExternMsg
?
=
null
,
@ProtoId
(
11
)
@JvmField
val
msgExternInfo
:
ExternMsg
?
=
null
,
@ProtoId
(
12
)
@JvmField
val
bytesUpIpV6
:
List
<
ByteArray
>?
=
null
,
@ProtoId
(
12
)
@JvmField
val
bytesUpIpV6
:
List
<
ByteArray
>?
=
null
,
@ProtoId
(
13
)
@JvmField
val
uint32UpV6Port
:
List
<
Int
>?
=
null
@ProtoId
(
13
)
@JvmField
val
uint32UpV6Port
:
List
<
Int
>?
=
null
)
:
ProtoBuf
)
:
ProtoBuf
@Serializable
@Serializable
internal
class
ReqBody
(
internal
class
ReqBody
(
@ProtoId
(
1
)
@JvmField
val
subcmd
:
Int
=
0
,
@ProtoId
(
1
)
@JvmField
val
subcmd
:
Int
=
0
,
@ProtoId
(
2
)
@JvmField
val
termType
:
Int
=
0
,
@ProtoId
(
2
)
@JvmField
val
termType
:
Int
=
0
,
@ProtoId
(
3
)
@JvmField
val
platformType
:
Int
=
0
,
@ProtoId
(
3
)
@JvmField
val
platformType
:
Int
=
0
,
...
@@ -73,7 +73,7 @@ internal class ReqBody(
...
@@ -73,7 +73,7 @@ internal class ReqBody(
)
:
ProtoBuf
)
:
ProtoBuf
@Serializable
@Serializable
internal
class
RspBody
(
internal
class
RspBody
(
@ProtoId
(
1
)
@JvmField
val
subcmd
:
Int
=
0
,
@ProtoId
(
1
)
@JvmField
val
subcmd
:
Int
=
0
,
@ProtoId
(
2
)
@JvmField
val
multimsgApplyupRsp
:
List
<
MultiMsg
.
MultiMsgApplyUpRsp
>?
=
null
,
@ProtoId
(
2
)
@JvmField
val
multimsgApplyupRsp
:
List
<
MultiMsg
.
MultiMsgApplyUpRsp
>?
=
null
,
@ProtoId
(
3
)
@JvmField
val
multimsgApplydownRsp
:
List
<
MultiMsg
.
MultiMsgApplyDownRsp
>?
=
null
@ProtoId
(
3
)
@JvmField
val
multimsgApplydownRsp
:
List
<
MultiMsg
.
MultiMsgApplyDownRsp
>?
=
null
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/MultiMsg.kt
View file @
1b4e1475
...
@@ -12,7 +12,8 @@
...
@@ -12,7 +12,8 @@
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.ForwardMessage
import
net.mamoe.mirai.message.data.asMessageChain
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.message.toRichTextElems
import
net.mamoe.mirai.qqandroid.message.toRichTextElems
import
net.mamoe.mirai.qqandroid.network.Packet
import
net.mamoe.mirai.qqandroid.network.Packet
...
@@ -42,12 +43,10 @@ internal class MessageValidationData @OptIn(MiraiInternalAPI::class) constructor
...
@@ -42,12 +43,10 @@ internal class MessageValidationData @OptIn(MiraiInternalAPI::class) constructor
}
}
@OptIn
(
MiraiInternalAPI
::
class
)
@OptIn
(
MiraiInternalAPI
::
class
)
internal
fun
Collection
<
MessageChain
>.
calculateValidationDataForGroup
(
internal
fun
Collection
<
ForwardMessage
.
INode
>.
calculateValidationDataForGroup
(
sequenceId
:
Int
,
sequenceId
:
Int
,
time
:
Int
,
random
:
UInt
,
random
:
UInt
,
groupCode
:
Long
,
groupCode
:
Long
,
botId
:
Long
,
botMemberNameCard
:
String
botMemberNameCard
:
String
):
MessageValidationData
{
):
MessageValidationData
{
...
@@ -55,9 +54,9 @@ internal fun Collection<MessageChain>.calculateValidationDataForGroup(
...
@@ -55,9 +54,9 @@ internal fun Collection<MessageChain>.calculateValidationDataForGroup(
msg
=
this
.
map
{
chain
->
msg
=
this
.
map
{
chain
->
MsgComm
.
Msg
(
MsgComm
.
Msg
(
msgHead
=
MsgComm
.
MsgHead
(
msgHead
=
MsgComm
.
MsgHead
(
fromUin
=
bot
Id
,
fromUin
=
chain
.
sender
Id
,
msgSeq
=
sequenceId
,
msgSeq
=
sequenceId
,
msgTime
=
time
,
msgTime
=
chain
.
time
,
msgUid
=
0
x01000000000000000L
or
random
.
toLong
(),
msgUid
=
0
x01000000000000000L
or
random
.
toLong
(),
mutiltransHead
=
MsgComm
.
MutilTransHead
(
mutiltransHead
=
MsgComm
.
MutilTransHead
(
status
=
0
,
status
=
0
,
...
@@ -66,13 +65,14 @@ internal fun Collection<MessageChain>.calculateValidationDataForGroup(
...
@@ -66,13 +65,14 @@ internal fun Collection<MessageChain>.calculateValidationDataForGroup(
msgType
=
82
,
// troop
msgType
=
82
,
// troop
groupInfo
=
MsgComm
.
GroupInfo
(
groupInfo
=
MsgComm
.
GroupInfo
(
groupCode
=
groupCode
,
groupCode
=
groupCode
,
groupCard
=
botMemberNameCard
// Cinnamon
groupCard
=
chain
.
senderName
// Cinnamon
),
),
isSrcMsg
=
false
isSrcMsg
=
false
),
),
msgBody
=
ImMsgBody
.
MsgBody
(
msgBody
=
ImMsgBody
.
MsgBody
(
richText
=
ImMsgBody
.
RichText
(
richText
=
ImMsgBody
.
RichText
(
elems
=
chain
.
toRichTextElems
(
forGroup
=
true
,
withGeneralFlags
=
false
).
toMutableList
()
elems
=
chain
.
message
.
asMessageChain
()
.
toRichTextElems
(
forGroup
=
true
,
withGeneralFlags
=
false
).
toMutableList
()
)
)
)
)
)
)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/ForwardMessage.kt
View file @
1b4e1475
...
@@ -7,42 +7,553 @@
...
@@ -7,42 +7,553 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
*/
@
file
:
Suppress
(
"MemberVisibilityCanBePrivate"
)
@
file
:
Suppress
(
"MemberVisibilityCanBePrivate"
,
"INVISIBLE_REFERENCE"
,
"INVISIBLE_MEMBER"
,
"unused"
)
package
net.mamoe.mirai.message.data
package
net.mamoe.mirai.message.data
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.message.ContactMessage
import
net.mamoe.mirai.message.data.ForwardMessage.DisplayStrategy
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.currentTimeSeconds
import
kotlin.jvm.JvmOverloads
import
kotlin.jvm.JvmSynthetic
/**
/**
* 合并转发
* 合并转发消息
*
* @param [displayStrategy] 卡片显示方案
*
* ### 显示方案
*
* #### 移动端
* 在移动客户端将会显示为卡片
*
* `<title>`: [DisplayStrategy.generateTitle]
*
* `<preview>`: [DisplayStrategy.generatePreview]
*
* `<summary>`: [DisplayStrategy.generateSummary]
*
* ```
* |-------------------------|
* | <title> |
* | <preview> |
* |-------------------------|
* | <summary> |
* |-------------------------|
* ```
*
* 默认显示方案:
* ```
* |-------------------------|
* | 群聊的聊天记录 |
* | <消息 1> |
* | <消息 2> |
* | <消息 3> |
* |-------------------------|
* | 查看 3 条转发消息 |
* |-------------------------|
* ```
*
* #### PC 端
* 在部分 PC 端显示为类似移动端的卡片, 在其他 PC 端显示为以下格式
* ```
* 鸽子 A 2020/04/23 11:27:54
* 咕
* 鸽子 B 2020/04/23 11:27:55
* 咕
* 鸽子 C 1970/01/01 08:00:00
* 咕咕咕
* ```
*
* ### 构造
* - 使用 [DSL][buildForwardMessage]
* - 通过 [ContactMessage] 集合转换: [toForwardMessage]
*
* @see buildForwardMessage
*/
*/
@SinceMirai
(
"0.39.0"
)
@SinceMirai
(
"0.39.0"
)
class
ForwardMessage
(
class
ForwardMessage
@JvmOverloads
constructor
(
val
messageList
:
Collection
<
MessageChain
>
/**
* 消息列表
*/
val
nodeList
:
Collection
<
INode
>,
val
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
)
:
MessageContent
{
)
:
MessageContent
{
companion
object
Key
:
Message
.
Key
<
ForwardMessage
>
{
/**
override
val
typeName
:
String
get
()
=
"ForwardMessage"
* @see ForwardMessage
*/
abstract
class
DisplayStrategy
{
/**
* 修改后卡片标题会变为 "转发的聊天记录", 而此函数的返回值会显示在 preview 前
*/
open
fun
generateTitle
(
forward
:
ForwardMessage
):
String
=
"群聊的聊天记录"
/**
* 显示在消息列表中的预览.
*/
open
fun
generateBrief
(
forward
:
ForwardMessage
):
String
=
"[聊天记录]"
/**
* 目前未发现在哪能显示
*/
open
fun
generateSource
(
forward
:
ForwardMessage
):
String
=
"聊天记录"
/**
* 显示在卡片 body 中, 只会显示 sequence 前四个元素.
* Java 用户: 使用 [sequenceOf] (`SequenceKt.sequenceOf`) 或 [asSequence] (`SequenceKt.asSequence`)
*/
open
fun
generatePreview
(
forward
:
ForwardMessage
):
Sequence
<
String
>
=
forward
.
nodeList
.
asSequence
().
map
{
it
.
senderName
+
": "
+
it
.
message
.
contentToString
()
}
/**
* 显示在卡片底部
*/
open
fun
generateSummary
(
forward
:
ForwardMessage
):
String
=
"查看 ${forward.nodeList.size} 条转发消息"
companion
object
Default
:
DisplayStrategy
()
{
@JvmSynthetic
inline
operator
fun
invoke
(
crossinline
generateTitle
:
(
forward
:
ForwardMessage
)
->
String
=
Default
::
generateTitle
,
crossinline
generateBrief
:
(
forward
:
ForwardMessage
)
->
String
=
Default
::
generateBrief
,
crossinline
generateSource
:
(
forward
:
ForwardMessage
)
->
String
=
Default
::
generateSource
,
crossinline
generatePreview
:
(
forward
:
ForwardMessage
)
->
Sequence
<
String
>
=
Default
::
generatePreview
,
crossinline
generateSummary
:
(
forward
:
ForwardMessage
)
->
String
=
Default
::
generateSummary
):
DisplayStrategy
=
object
:
DisplayStrategy
()
{
override
fun
generateTitle
(
forward
:
ForwardMessage
):
String
=
generateTitle
(
forward
)
override
fun
generateBrief
(
forward
:
ForwardMessage
):
String
=
generateBrief
(
forward
)
override
fun
generateSource
(
forward
:
ForwardMessage
):
String
=
generateSource
(
forward
)
override
fun
generatePreview
(
forward
:
ForwardMessage
):
Sequence
<
String
>
=
generatePreview
(
forward
)
override
fun
generateSummary
(
forward
:
ForwardMessage
):
String
=
generateSummary
(
forward
)
}
}
}
}
override
fun
toString
():
String
=
"[mirai:forward:$messageList]"
data class
Node
(
override
val
senderId
:
Long
,
override
val
time
:
Int
,
override
val
senderName
:
String
,
override
val
message
:
Message
)
:
INode
interface
INode
{
/**
* 发送人 [User.id]
*/
val
senderId
:
Long
/**
* 时间戳秒
*/
val
time
:
Int
/**
* 发送人名称
*/
val
senderName
:
String
private
val
contentToString
:
String
by
lazy
{
/**
messageList
.
joinToString
(
"\n"
)
* 消息内容
*/
val
message
:
Message
}
}
@MiraiExperimentalAPI
companion
object
Key
:
Message
.
Key
<
ForwardMessage
>
{
override
fun
contentToString
():
String
=
contentToString
override
val
typeName
:
String
get
()
=
"ForwardMessage"
}
override
val
length
:
Int
override
fun
toString
():
String
=
"[mirai:forward:$nodeList]"
get
()
=
contentToString
.
length
private
val
contentToString
:
String
by
lazy
{
nodeList
.
joinToString
(
"\n"
)
}
@MiraiExperimentalAPI
override
fun
contentToString
():
String
=
contentToString
override
val
length
:
Int
get
()
=
contentToString
.
length
override
fun
get
(
index
:
Int
):
Char
=
contentToString
[
length
]
override
fun
get
(
index
:
Int
):
Char
=
contentToString
[
length
]
override
fun
subSequence
(
startIndex
:
Int
,
endIndex
:
Int
):
CharSequence
=
override
fun
subSequence
(
startIndex
:
Int
,
endIndex
:
Int
):
CharSequence
=
contentToString
.
subSequence
(
startIndex
,
endIndex
)
contentToString
.
subSequence
(
startIndex
,
endIndex
)
override
fun
compareTo
(
other
:
String
):
Int
=
contentToString
.
compareTo
(
other
)
override
fun
compareTo
(
other
:
String
):
Int
=
contentToString
.
compareTo
(
other
)
}
}
/**
* 转换为 [ForwardMessage]
*/
@SinceMirai
(
"0.39.0"
)
@JvmOverloads
fun
Iterable
<
ContactMessage
>.
toForwardMessage
(
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
):
ForwardMessage
{
val
iterator
=
this
.
iterator
()
if
(!
iterator
.
hasNext
())
return
ForwardMessage
(
emptyList
(),
displayStrategy
)
return
ForwardMessage
(
this
.
map
{
ForwardMessage
.
Node
(
it
.
sender
.
id
,
it
.
time
,
it
.
senderName
,
it
.
message
)
},
displayStrategy
)
}
/**
* 转换为 [ForwardMessage]
*/
fun
Message
.
toForwardMessage
(
sender
:
User
,
time
:
Int
=
currentTimeSeconds
.
toInt
(),
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
):
ForwardMessage
=
this
.
toForwardMessage
(
sender
.
id
,
sender
.
nameCardOrNick
,
time
,
displayStrategy
)
/**
* 转换为 [ForwardMessage]
*/
@SinceMirai
(
"0.39.0"
)
@JvmOverloads
fun
Message
.
toForwardMessage
(
senderId
:
Long
,
senderName
:
String
,
time
:
Int
=
currentTimeSeconds
.
toInt
(),
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
):
ForwardMessage
=
ForwardMessage
(
listOf
(
ForwardMessage
.
Node
(
senderId
,
time
,
senderName
,
this
)),
displayStrategy
)
/**
* 构造一条 [ForwardMessage]
*
* @see ForwardMessageBuilder 查看 DSL 帮助
* @see ForwardMessage 查看转发消息说明
*/
@SinceMirai
(
"0.39.0"
)
@JvmSynthetic
inline
fun
buildForwardMessage
(
context
:
Contact
,
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
,
block
:
ForwardMessageBuilder
.()
->
Unit
):
ForwardMessage
=
ForwardMessageBuilder
(
context
).
apply
{
this
.
displayStrategy
=
displayStrategy
}.
apply
(
block
).
build
()
/**
* 使用 DSL 构建一个 [ForwardMessage].
*
* @see ForwardMessageBuilder 查看 DSL 帮助
* @see ForwardMessage 查看转发消息说明
*/
@SinceMirai
(
"0.39.0"
)
@JvmSynthetic
inline
fun
ContactMessage
.
buildForwardMessage
(
context
:
Contact
=
this
.
subject
,
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
,
block
:
ForwardMessageBuilder
.()
->
Unit
):
ForwardMessage
=
ForwardMessageBuilder
(
context
).
apply
{
this
.
displayStrategy
=
displayStrategy
}.
apply
(
block
).
build
()
/**
* 标记转发消息 DSL
*/
@SinceMirai
(
"0.39.0"
)
@Target
(
AnnotationTarget
.
FUNCTION
,
AnnotationTarget
.
TYPE
)
@DslMarker
annotation
class
ForwardMessageDsl
/**
* 转发消息 DSL 构建器.
*
* # 总览
*
* 使用 DSL 构造一个转发:
* ```
* buildForwardMessage {
* 123456789 named "鸽子 A" says "咕" // 意为 名为 "鸽子 A" 的用户 123456789 发送了一条内容为 "咕" 的消息
* 100200300 named "鸽子 C" at 1582315452 says "咕咕咕" // at 设置时间 (在 PC 端显示, 在手机端不影响顺序)
* 987654321 named "鸽子 B" says "咕" // 未指定时间, 则自动顺序安排时间
* 5555555 says "咕" // 未指定发送人
* bot says { // 构造消息链, 同 `buildMessageChain`
* +"发个图片试试"
* +Image("{90CCED1C-2D64-313B-5D66-46625CAB31D7}.jpg")
* }
* val member: Member = ...
* member says "我是幸运群员" // 使用 `User says` 则会同时设置发送人名称
* }
* ```
*
* # 语法
*
* 下文中 `S` 代表消息发送人. 可接受: 发送人账号 id([Long] 或 [Int]) 或 [User]
* 下文中 `M` 代表消息内容. 可接受: [String], [Message], 或 [构造消息链][MessageChainBuilder] 的 DSL 代码块
*
* ## 陈述一条消息
* 使用 [`infix fun S.says(M)`][ForwardMessageBuilder.says]
*
* 语句 `123456789 named "鸽子 A" says "咕"` 创建并添加了一条名为 "鸽子 A" 的用户 123456789 发送的内容为 "咕" 的消息
*
*
* ### 陈述
* 一条 '陈述' 必须包含以下属性:
* - 发送人. 只可以作为 infix 函数的接收者 (receiver) 设置, 如 `sender says M`, `sender named "xxx"`, `sender at 123`
* - 消息内容. 只可以通过 `says` 函数的参数设置, 即 `says M`.
*
* ### 组合陈述
* 现支持的可选属性为 `named`, `at`
*
*
* 最基础的陈述为 `S says M`. 可在 `says` 前按任意顺序添加组合属性:
*
* `S named "xxx" says M`;
*
* `S at 123456 says M`; 其中 `123456` 为发信时间
*
*
* 属性的顺序并不重要. 如下两句陈述效果相同.
*
* `S named "xxx" at 123456 says M`;
*
* `S at 123456 named "xxx" says M`;
*
* ### 重复属性
* 若属性有重复, **新属性会替换旧属性**.
*
* `S named "name1" named "name2" says M` 最终的发送人名称为 `"name2"`
*/
@SinceMirai
(
"0.39.0"
)
class
ForwardMessageBuilder
private
constructor
(
/**
* 消息语境. 可为 [Group] 或 [User]
*/
val
context
:
Contact
,
private
val
container
:
MutableList
<
ForwardMessage
.
INode
>
)
:
MutableList
<
ForwardMessage
.
INode
>
by
container
{
/**
* @see ForwardMessage.displayStrategy
*/
var
displayStrategy
:
DisplayStrategy
=
DisplayStrategy
private
var
built
:
Boolean
=
false
private
fun
checkBuilt
()
{
check
(!
built
)
{
"ForwardMessageBuilder is already built therefore can't be modified"
}
}
constructor
(
context
:
Contact
)
:
this
(
context
,
mutableListOf
())
constructor
(
context
:
Contact
,
initialSize
:
Int
)
:
this
(
context
,
ArrayList
<
ForwardMessage
.
INode
>(
initialSize
))
/**
* 当前时间.
* 在使用 [says] 时若不指定之间, 则会使用 [currentTime] 自增 1 的事件.
*/
var
currentTime
:
Int
=
currentTimeSeconds
.
toInt
()
inner
class
BuilderNode
:
ForwardMessage
.
INode
{
/**
* 发送人 [User.id]
*/
override
var
senderId
:
Long
=
0
/**
* 时间戳秒
*/
override
var
time
:
Int
=
currentTime
++
/**
* 发送人名称
*/
override
var
senderName
:
String
=
""
/**
* 消息内容
*/
override
lateinit
var
message
:
Message
/**
* 指定发送人 id 和名称.
*/
@ForwardMessageDsl
infix
fun
sender
(
user
:
User
):
BuilderNode
=
apply
{
this
.
senderId
(
user
.
id
);
this
.
named
(
user
.
nameCardOrNick
)
}
/**
* 指定发送人 id.
*/
@ForwardMessageDsl
infix
fun
senderId
(
id
:
Int
):
BuilderNode
=
apply
{
this
.
senderId
=
id
.
toLongUnsigned
()
}
/**
* 指定发送人 id.
*/
@ForwardMessageDsl
infix
fun
senderId
(
id
:
Long
):
BuilderNode
=
apply
{
this
.
senderId
=
id
}
/**
* 指定发送人名称.
*/
@ForwardMessageDsl
infix
fun
named
(
name
:
String
):
BuilderNode
=
apply
{
this
.
senderName
=
name
}
/**
* 指定发送人名称.
*/
@ForwardMessageDsl
infix
fun
senderName
(
name
:
String
):
BuilderNode
=
apply
{
this
.
senderName
=
name
}
/**
* 指定时间.
* @time 时间戳, 单位为秒
*/
@ForwardMessageDsl
infix
fun
at
(
time
:
Int
):
BuilderNode
=
this
.
apply
{
this
.
time
=
time
}
/**
* 指定时间.
* @time 时间戳, 单位为秒
*/
@ForwardMessageDsl
infix
fun
time
(
time
:
Int
):
BuilderNode
=
this
.
apply
{
this
.
time
=
time
}
/**
* 指定消息内容
*/
@ForwardMessageDsl
infix
fun
message
(
message
:
Message
):
BuilderNode
=
this
.
apply
{
this
.
message
=
message
}
/**
* 指定消息内容
*/
@ForwardMessageDsl
infix
fun
message
(
message
:
String
):
BuilderNode
=
this
.
apply
{
this
.
message
=
message
.
toMessage
()
}
/** 添加一条消息 */
@ForwardMessageDsl
infix
fun
says
(
message
:
Message
):
ForwardMessageBuilder
=
this
@ForwardMessageBuilder
.
apply
{
checkBuilt
()
this
@BuilderNode
.
message
=
message
add
(
this
@BuilderNode
)
}
/** 添加一条消息 */
@ForwardMessageDsl
infix
fun
says
(
message
:
String
):
ForwardMessageBuilder
=
this
.
says
(
message
.
toMessage
())
/** 构造并添加一个 [MessageChain] */
@ForwardMessageDsl
inline
infix
fun
says
(
chain
:
@ForwardMessageDsl
MessageChainBuilder
.()
->
Unit
):
ForwardMessageBuilder
=
says
(
MessageChainBuilder
().
apply
(
chain
).
asMessageChain
())
}
// region general `says`
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
Long
.
says
(
message
:
String
):
ForwardMessageBuilder
=
says
(
message
.
toMessage
())
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
Int
.
says
(
message
:
String
):
ForwardMessageBuilder
=
this
.
toLong
().
and
(
0
xFFFF_FFFF
).
says
(
message
.
toMessage
())
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
Long
.
says
(
message
:
Message
):
ForwardMessageBuilder
=
this
@ForwardMessageBuilder
.
apply
{
checkBuilt
()
add
(
BuilderNode
().
apply
{
senderId
=
this
@
says
this
.
message
=
message
})
}
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
Int
.
says
(
message
:
Message
):
ForwardMessageBuilder
=
this
.
toLong
().
and
(
0
xFFFF_FFFF
).
says
(
message
)
/** 构造并添加一个 [MessageChain], 自动按顺序调整时间 */
@ForwardMessageDsl
inline
infix
fun
Long
.
says
(
chain
:
@ForwardMessageDsl
MessageChainBuilder
.()
->
Unit
):
ForwardMessageBuilder
=
says
(
MessageChainBuilder
().
apply
(
chain
).
asMessageChain
())
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
inline
infix
fun
Int
.
says
(
chain
:
@ForwardMessageDsl
MessageChainBuilder
.()
->
Unit
):
ForwardMessageBuilder
=
this
.
toLong
().
and
(
0
xFFFF_FFFF
).
says
(
chain
)
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
Bot
.
says
(
message
:
String
):
ForwardMessageBuilder
=
this
.
id
named
this
.
smartName
()
says
message
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
User
.
says
(
message
:
String
):
ForwardMessageBuilder
=
this
.
id
named
this
.
nameCardOrNick
says
message
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
User
.
says
(
message
:
Message
):
ForwardMessageBuilder
=
this
.
id
named
this
.
nameCardOrNick
says
message
/** 添加一条消息, 自动按顺序调整时间 */
@ForwardMessageDsl
infix
fun
Bot
.
says
(
message
:
Message
):
ForwardMessageBuilder
=
this
.
id
named
this
.
smartName
()
says
message
/** 构造并添加一个 [MessageChain], 自动按顺序调整时间 */
@ForwardMessageDsl
inline
infix
fun
User
.
says
(
chain
:
@ForwardMessageDsl
MessageChainBuilder
.()
->
Unit
):
ForwardMessageBuilder
=
this
says
(
MessageChainBuilder
().
apply
(
chain
).
asMessageChain
())
/** 构造并添加一个 [MessageChain], 自动按顺序调整时间 */
@ForwardMessageDsl
inline
infix
fun
Bot
.
says
(
chain
:
@ForwardMessageDsl
MessageChainBuilder
.()
->
Unit
):
ForwardMessageBuilder
=
this
says
(
MessageChainBuilder
().
apply
(
chain
).
asMessageChain
())
// endregion
// region timed
/**
* 为一条消息指定时间.
* @time 时间戳, 单位为秒
*/
@ForwardMessageDsl
infix
fun
Int
.
at
(
time
:
Int
):
BuilderNode
=
this
.
toLongUnsigned
()
at
time
/**
* 为一条消息指定时间.
* @time 时间戳, 单位为秒
*/
@ForwardMessageDsl
infix
fun
Long
.
at
(
time
:
Int
):
BuilderNode
=
BuilderNode
().
apply
{
senderId
=
this
@
at
;
this
.
time
=
time
}
/**
* 为一条消息指定时间和发送人名称.
* @time 时间戳, 单位为秒
*/
@ForwardMessageDsl
infix
fun
User
.
at
(
time
:
Int
):
BuilderNode
=
this
.
id
named
this
.
nameCardOrNick
at
time
// endregion
// region named
/** 为一条消息指定发送人名称. */
@ForwardMessageDsl
infix
fun
Int
.
named
(
name
:
String
):
BuilderNode
=
this
.
toLongUnsigned
().
named
(
name
)
/** 为一条消息指定发送人名称. */
@ForwardMessageDsl
infix
fun
Long
.
named
(
name
:
String
):
BuilderNode
=
BuilderNode
().
apply
{
senderId
=
this
@
named
;
this
.
senderName
=
name
}
/** 为一条消息指定发送人名称. */
@ForwardMessageDsl
infix
fun
User
.
named
(
name
:
String
):
BuilderNode
=
this
.
id
.
named
(
name
)
// endregion
/** 构造 [ForwardMessage] */
fun
build
():
ForwardMessage
=
ForwardMessage
(
container
.
toList
(),
this
.
displayStrategy
)
@Suppress
(
"NOTHING_TO_INLINE"
)
private
inline
fun
Int
.
toLongUnsigned
():
Long
=
this
.
toLong
().
and
(
0
xFFFF_FFFF
)
@OptIn
(
MiraiExperimentalAPI
::
class
)
internal
fun
Bot
.
smartName
():
String
=
when
(
val
c
=
this
@ForwardMessageBuilder
.
context
)
{
is
Group
->
c
.
botAsMember
.
nameCardOrNick
else
->
nick
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt
View file @
1b4e1475
...
@@ -358,6 +358,7 @@ interface ConstrainSingle<out M : Message> : MessageMetadata {
...
@@ -358,6 +358,7 @@ interface ConstrainSingle<out M : Message> : MessageMetadata {
* @see Image 图片
* @see Image 图片
* @see RichMessage 富文本
* @see RichMessage 富文本
* @see Face 原生表情
* @see Face 原生表情
* @see ForwardMessage 合并转发
*/
*/
interface
MessageContent
:
SingleMessage
interface
MessageContent
:
SingleMessage
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/RichMessage.kt
View file @
1b4e1475
...
@@ -13,6 +13,7 @@
...
@@ -13,6 +13,7 @@
package
net.mamoe.mirai.message.data
package
net.mamoe.mirai.message.data
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.annotation.AnnotationTarget.*
import
kotlin.annotation.AnnotationTarget.*
...
@@ -151,6 +152,8 @@ constructor(serviceId: Int = 60, content: String) : ServiceMessage(serviceId, co
...
@@ -151,6 +152,8 @@ constructor(serviceId: Int = 60, content: String) : ServiceMessage(serviceId, co
/**
/**
* 长消息.
* 长消息.
*
* 不需要手动区分长消息和普通消息, 在 [Contact.sendMessage] 时会自动判断.
*/
*/
@SinceMirai
(
"0.31.0"
)
@SinceMirai
(
"0.31.0"
)
@MiraiExperimentalAPI
@MiraiExperimentalAPI
...
@@ -164,8 +167,8 @@ class LongMessage internal constructor(content: String, val resId: String) : Ser
...
@@ -164,8 +167,8 @@ class LongMessage internal constructor(content: String, val resId: String) : Ser
* 合并转发消息
* 合并转发消息
* @suppress 此 API 非常不稳定
* @suppress 此 API 非常不稳定
*/
*/
@OptIn
(
MiraiExperimentalAPI
::
class
)
@SinceMirai
(
"0.39.0"
)
@SinceMirai
(
"0.39.0"
)
@MiraiExperimentalAPI
(
"此 API 非常不稳定"
)
internal
class
ForwardMessageInternal
(
content
:
String
)
:
ServiceMessage
(
35
,
content
)
internal
class
ForwardMessageInternal
(
content
:
String
)
:
ServiceMessage
(
35
,
content
)
/*
/*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment