()
- override fun sendMessage(message: Message) {
+ override fun sendMessage(message: MessageChain) {
robot.network.messageHandler.sendGroupMessage(this, message)
}
@@ -23,7 +34,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
companion object {
@JvmStatic
- fun groupNumberToId(number: Long): Long {
+ fun groupNumberToId(number: Long): Long {//求你别出错
val left: Long = number.toString().let {
if (it.length < 6) {
return@groupNumberToId number
@@ -61,7 +72,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
}
@JvmStatic
- fun groupIdToNumber(id: Long): Long {
+ fun groupIdToNumber(id: Long): Long {//求你别出错
var left: Long = id.toString().let {
if (it.length < 6) {
return@groupIdToNumber id
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
index af009045e..eebcd728f 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
@@ -3,18 +3,22 @@ package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.defaults.At
+import net.mamoe.mirai.message.defaults.MessageChain
/**
* QQ 账号.
* 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Robot].
*
+ * Java 获取 qq 号: `qq.getNumber()`
+ * Java 获取所属 robot: `qq.getRobot()`
+ *
* A QQ instance helps you to receive message from or send message to.
* Notice that, one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same.
*
* @author Him188moe
*/
class QQ(robot: Robot, number: Long) : Contact(robot, number) {
- override fun sendMessage(message: Message) {
+ override fun sendMessage(message: MessageChain) {
robot.network.messageHandler.sendFriendMessage(this, message)
}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java
index 38d18b5a4..400f0c0ac 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java
@@ -12,19 +12,14 @@ import java.util.Objects;
*/
public final class FriendMessageEvent extends FriendEvent {
private final MessageChain messageChain;
- private final String messageString;
public FriendMessageEvent(@NotNull Robot robot, @NotNull QQ sender, @NotNull MessageChain messageChain) {
super(robot, sender);
this.messageChain = Objects.requireNonNull(messageChain);
- this.messageString = messageChain.toString();
}
- public String getMessageString() {
- return messageString;
- }
-
- public MessageChain getMessageChain() {
+ @NotNull
+ public MessageChain message() {
return messageChain;
}
}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java
deleted file mode 100644
index 81c41ce2a..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package net.mamoe.mirai.message;
-
-import net.mamoe.mirai.contact.Contact;
-import net.mamoe.mirai.contact.QQ;
-import net.mamoe.mirai.message.defaults.At;
-import net.mamoe.mirai.message.defaults.Image;
-import net.mamoe.mirai.message.defaults.MessageChain;
-import net.mamoe.mirai.message.defaults.PlainText;
-import org.jetbrains.annotations.NotNull;
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.util.Objects;
-
-/**
- * 可发送的或从服务器接收的消息.
- * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 {@linkplain PlainText 纯文本}, {@linkplain Image 图片} 等.
- *
- * @author Him188moe
- * @see Contact#sendMessage(Message) 发送这个消息
- * @see MessageKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现
- */
-public abstract class Message {
- @Override
- public abstract String toString();
-
- public String toDebugString() {
- return this.getClass().getSimpleName() + String.format("(%s)", this.toString());
- }
-
- /**
- * 把这个消息连接到另一个消息的头部. 相当于字符串相加
- *
- * Connects this Message to the head of another Message.
- * That is, another message becomes the tail of this message.
- * This method does similar to {@link String#concat(String)}
- *
- * E.g.:
- * PlainText a = new PlainText("Hello ");
- * PlainText b = new PlainText("world");
- * PlainText c = a.concat(b);
- *
- * the text of c is "Hello world"
- *
- * @param tail tail
- * @return message connected
- */
- public Message concat(@NotNull Message tail) {
- return new MessageChain(this, Objects.requireNonNull(tail));
- }
-
- public final Message concat(String tail) {
- return concat(new PlainText(tail));
- }
-
-
- public Message withImage(String imageId) {
-
- // TODO: 2019/9/1
- return this;
- }
-
- public Message withImage(BufferedImage image) {
- // TODO: 2019/9/1
- return this;
-
- }
-
- public Message withImage(File image) {
- // TODO: 2019/9/1
- return this;
- }
-
- public Message withAt(@NotNull QQ target) {
- this.concat(target.at());
- return this;
- }
-
- public Message withAt(int target) {
- this.concat(new At(target));
- return this;
- }
-
-}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
new file mode 100644
index 000000000..15cfc30a9
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
@@ -0,0 +1,174 @@
+package net.mamoe.mirai.message
+
+import net.mamoe.mirai.contact.Contact
+import net.mamoe.mirai.contact.QQ
+import net.mamoe.mirai.message.defaults.At
+import net.mamoe.mirai.message.defaults.Image
+import net.mamoe.mirai.message.defaults.MessageChain
+import net.mamoe.mirai.message.defaults.PlainText
+import java.awt.image.BufferedImage
+import java.io.File
+import java.util.*
+
+
+/**
+ * 可发送的或从服务器接收的消息.
+ * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等.
+ *
+ * 在 Kotlin, 使用 [Message] 与使用 [String] 几乎没有什么用法上的区别.
+ *
+ * @author Him188moe
+ * @see Contact.sendMessage
+ */
+abstract class Message {
+ internal abstract val type: Int
+
+ private var toStringCache: String? = null
+ private val cacheLock = object : Any() {}
+
+ internal abstract fun toStringImpl(): String
+
+ /**
+ * 得到用户层的文本消息. 如:
+ * - [PlainText] 得到 消息内容
+ * - [Image] 得到 "{ID}.png"
+ * - [At] 得到 "[@qq]"
+ */
+ final override fun toString(): String {
+ synchronized(cacheLock) {
+ if (toStringCache != null) {
+ return toStringCache!!
+ }
+
+ this.toStringCache = toStringImpl()
+ return toStringCache!!
+ }
+ }
+
+ internal fun clearToStringCache() {
+ synchronized(cacheLock) {
+ toStringCache = null
+ }
+ }
+
+ /**
+ * 得到类似 "PlainText(内容)", "Image(ID)"
+ */
+ open fun toObjectString(): String {
+ return this.javaClass.simpleName + String.format("(%s)", this.toString())
+ }
+
+ /**
+ * 转换为数据包使用的 byte array
+ */
+ abstract fun toByteArray(): ByteArray
+
+
+ /**
+ * 比较两个 Message 的内容是否相等. 如:
+ * - [PlainText] 比较 [PlainText.text]
+ * - [Image] 比较 [Image.imageID]
+ */
+ abstract infix fun valueEquals(another: Message): Boolean
+
+ /**
+ * 将这个消息的 [toString] 与 [another] 比较
+ */
+ infix fun valueEquals(another: String): Boolean = this.toString() == another
+
+ /**
+ * 把这个消息连接到另一个消息的头部. 相当于字符串相加
+ *
+ *
+ * Connects this Message to the head of another Message.
+ * That is, another message becomes the tail of this message.
+ * This method does similar to [String.concat]
+ *
+ *
+ * E.g.:
+ * PlainText a = new PlainText("Hello ");
+ * PlainText b = new PlainText("world");
+ * PlainText c = a.concat(b);
+ *
+ *
+ * the text of c is "Hello world"
+ *
+ * @param tail tail
+ * @return message connected
+ */
+ open fun concat(tail: Message): Message {
+ return MessageChain(this, Objects.requireNonNull(tail))
+ }
+
+ fun concat(tail: String): Message {
+ return concat(PlainText(tail))
+ }
+
+
+ fun withImage(imageId: String): Message {
+
+ // TODO: 2019/9/1
+ return this
+ }
+
+ fun withImage(image: BufferedImage): Message {
+ // TODO: 2019/9/1
+ return this
+
+ }
+
+ fun withImage(image: File): Message {
+ // TODO: 2019/9/1
+ return this
+ }
+
+ fun withAt(target: QQ): Message {
+ this.concat(target.at())
+ return this
+ }
+
+ fun withAt(target: Int): Message {
+ this.concat(At(target.toLong()))
+ return this
+ }
+
+ open fun toChain(): MessageChain {
+ return MessageChain(this)
+ }
+
+
+ /* For Kotlin */
+
+ /**
+ * 实现使用 '+' 操作符连接 [Message] 与 [Message]
+ */
+ infix operator fun plus(another: Message): Message = this.concat(another)
+
+ /**
+ * 实现使用 '+' 操作符连接 [Message] 与 [String]
+ */
+ infix operator fun plus(another: String): Message = this.concat(another)
+
+ /**
+ * 实现使用 '+' 操作符连接 [Message] 与 [Number]
+ */
+ infix operator fun plus(another: Number): Message = this.concat(another.toString())
+
+ /**
+ * 连接 [String] 与 [Message]
+ */
+ fun String.concat(another: Message): Message = PlainText(this).concat(another)
+
+ override fun hashCode(): Int {
+ return javaClass.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is Message) return false
+
+ if (type != other.type) return false
+
+ return this.toString() == other.toString()
+ }
+}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageId.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageId.kt
new file mode 100644
index 000000000..4e4f3dcad
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageId.kt
@@ -0,0 +1,22 @@
+package net.mamoe.mirai.message
+
+/**
+ * [Message] 在数据包中的 id([UByte])
+ *
+ * Java 调用方式:
+ * MessageId.at
+ *
+ * @author Him188moe
+ */
+object MessageId {
+
+ const val AT: Int = 0x00//todo 不知道是多少
+
+ const val FACE: Int = 0x00//todo 不知道是多少
+
+ const val TEXT: Int = 0x01
+
+ const val IMAGE: Int = 0x06
+
+ const val CHAIN: Int = 0xff//仅用于 equals. Packet 中不存在 Chain 概念
+}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt
deleted file mode 100644
index 0257cbf57..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-@file:JvmName("MessageKt")
-
-package net.mamoe.mirai.message
-
-import net.mamoe.mirai.message.defaults.PlainText
-
-/**
- * 实现使用 '+' 操作符连接 [Message] 与 [Message]
- */
-infix operator fun Message.plus(another: Message): Message = this.concat(another)
-
-/**
- * 实现使用 '+' 操作符连接 [Message] 与 [String]
- */
-infix operator fun Message.plus(another: String): Message = this.concat(another)
-
-/**
- * 连接 [String] 与 [Message]
- */
-infix fun String.concat(another: Message): Message = PlainText(this).concat(another)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java
deleted file mode 100644
index dbae4f45a..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package net.mamoe.mirai.message.defaults;
-
-import net.mamoe.mirai.contact.QQ;
-import net.mamoe.mirai.message.Message;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Objects;
-
-/**
- * At 一个人的消息.
- *
- * @author Him188moe
- */
-public final class At extends Message {
- private final long target;
-
- public At(@NotNull QQ target) {
- this(Objects.requireNonNull(target).getNumber());
- }
-
- public At(long target) {
- this.target = target;
- }
-
- public long getTarget() {
- return target;
- }
-
- @Override
- public String toString() {
- // TODO: 2019/9/4 At.toString
- throw new UnsupportedOperationException();
- }
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt
new file mode 100644
index 000000000..904e474cf
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt
@@ -0,0 +1,30 @@
+package net.mamoe.mirai.message.defaults
+
+import net.mamoe.mirai.contact.QQ
+import net.mamoe.mirai.message.Message
+import net.mamoe.mirai.message.MessageId
+
+/**
+ * At 一个人
+ *
+ * @author Him188moe
+ */
+class At(val target: Long) : Message() {
+ override val type: Int = MessageId.AT
+
+ constructor(target: QQ) : this(target.number)
+
+ override fun toStringImpl(): String = "[@$target]"
+
+ override fun toByteArray(): ByteArray {
+ TODO()
+ }
+
+ override fun valueEquals(another: Message): Boolean {
+ if (another !is At) {
+ return false
+ }
+
+ return another.target == this.target
+ }
+}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java
deleted file mode 100644
index 0f5f2cd6b..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package net.mamoe.mirai.message.defaults;
-
-import net.mamoe.mirai.message.FaceID;
-import net.mamoe.mirai.message.Message;
-
-/**
- * QQ 自带表情
- *
- * @author Him188moe
- */
-public final class Face extends Message {
- private final FaceID id;
-
- public Face(FaceID id) {
- this.id = id;
- }
-
- public FaceID getId() {
- return id;
- }
-
- @Override
- public String toString() {
- if (id == null) {
- return "[face?]";
-
- }
- return String.format("[face%d]", id.getId());
- }
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
new file mode 100644
index 000000000..56a5fba4d
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
@@ -0,0 +1,33 @@
+package net.mamoe.mirai.message.defaults
+
+import net.mamoe.mirai.message.FaceID
+import net.mamoe.mirai.message.Message
+import net.mamoe.mirai.message.MessageId
+
+/**
+ * QQ 自带表情
+ *
+ * @author Him188moe
+ */
+class Face(val id: FaceID?) : Message() {
+ override val type: Int = MessageId.FACE
+
+ override fun toStringImpl(): String {
+ return if (id == null) {
+ "[face?]"
+
+ } else String.format("[face%d]", id.id)
+ }
+
+ override fun toByteArray(): ByteArray {
+ TODO()
+ }
+
+ override fun valueEquals(another: Message): Boolean {
+ if (another !is Face) {
+ return false
+ }
+ return this.id == another.id
+ }
+}
+
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.java
deleted file mode 100644
index 565be2fe3..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.mamoe.mirai.message.defaults;
-
-import net.mamoe.mirai.message.Message;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.*;
-import java.net.URL;
-
-/**
- * @author Him188moe
- */
-public final class Image extends Message {
- private String imageID;
-
- public Image(InputStream inputStream) {
-
- }
-
- public Image(BufferedImage image) {
-
- }
-
- public Image(File imageFile) throws FileNotFoundException {
- this(new FileInputStream(imageFile));
- }
-
- public Image(URL url) throws IOException {
- this(ImageIO.read(url));
- }
-
- /**
- * {xxxxx}.jpg
- *
- * @param imageID
- */
- public Image(String imageID) {
- this.imageID = imageID;
- }
-
- @Override
- public String toString() {
- return imageID;
- }
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
new file mode 100644
index 000000000..b168c250c
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
@@ -0,0 +1,57 @@
+package net.mamoe.mirai.message.defaults
+
+import net.mamoe.mirai.message.Message
+import net.mamoe.mirai.message.MessageId
+import java.awt.image.BufferedImage
+import java.io.*
+import java.net.URL
+import javax.imageio.ImageIO
+
+/**
+ * @author Him188moe
+ */
+class Image : Message {
+ override val type: Int = MessageId.IMAGE
+
+ private var imageID: String? = null
+
+ constructor(inputStream: InputStream) {
+
+ }
+
+ constructor(image: BufferedImage) {
+
+ }
+
+ @Throws(FileNotFoundException::class)
+ constructor(imageFile: File) : this(FileInputStream(imageFile)) {
+ }
+
+ @Throws(IOException::class)
+ constructor(url: URL) : this(ImageIO.read(url)) {
+ }
+
+ /**
+ * {xxxxx}.jpg
+ *
+ * @param imageID
+ */
+ constructor(imageID: String) {
+ this.imageID = imageID
+ }
+
+ override fun toStringImpl(): String {
+ return imageID!!
+ }
+
+ override fun toByteArray(): ByteArray {
+ TODO()
+ }
+
+ override fun valueEquals(another: Message): Boolean {
+ if (another !is Image) {
+ return false
+ }
+ return this.imageID == another.imageID
+ }
+}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java
deleted file mode 100644
index 00fb54944..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.mamoe.mirai.message.defaults;
-
-import net.mamoe.mirai.message.Message;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * @author Him188moe
- */
-public final class MessageChain extends Message {
- private LinkedList list = new LinkedList<>();
-
- public MessageChain(@NotNull Message head, @NotNull Message tail) {
- Objects.requireNonNull(head);
- Objects.requireNonNull(tail);
-
- list.add(head);
- list.add(tail);
- }
-
- public MessageChain(@NotNull Message message) {
- Objects.requireNonNull(message);
- list.add(message);
- }
-
- public MessageChain() {
- }
-
-
- /**
- * @return An unmodifiable list
- */
- public List toList() {
- return List.copyOf(list);
- }
-
- public Stream stream() {
- return new ArrayList<>(list).stream();
- }
-
- @Override
- public synchronized String toString() {
- return this.list.stream().map(Message::toString).collect(Collectors.joining(""));
- }
-
- public synchronized String toDebugString() {
- return String.format("MessageChain(%s)", this.list.stream().map(Message::toDebugString).collect(Collectors.joining(", ")));
- }
-
- @Override
- public synchronized Message concat(@NotNull Message tail) {
- this.list.add(tail);
- return this;
- }
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
new file mode 100644
index 000000000..18dd74ad4
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
@@ -0,0 +1,71 @@
+package net.mamoe.mirai.message.defaults
+
+import net.mamoe.mirai.message.Message
+import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.utils.lazyEncode
+import java.util.*
+import java.util.stream.Collectors
+import java.util.stream.Stream
+
+class MessageChain : Message {
+ override val type: Int = MessageId.CHAIN
+
+ internal val list = LinkedList()
+
+ constructor(head: Message, tail: Message) {
+ Objects.requireNonNull(head)
+ Objects.requireNonNull(tail)
+
+ list.add(head)
+ list.add(tail)
+ }
+
+ constructor(message: Message) {
+ Objects.requireNonNull(message)
+ list.add(message)
+ }
+
+ constructor()
+
+ fun toList(): List {
+ return list.toList()
+ }
+
+ fun stream(): Stream {
+ return ArrayList(list).stream()
+ }
+
+ @Synchronized
+ override fun toStringImpl(): String {
+ return this.list.stream().map { it.toString() }.collect(Collectors.joining(""))
+ }
+
+ @Synchronized
+ override fun toObjectString(): String {
+ return String.format("MessageChain(%s)", this.list.stream().map { it.toObjectString() }.collect(Collectors.joining(", ")))
+ }
+
+ @Synchronized
+ override fun concat(tail: Message): Message {
+ this.list.add(tail)
+ clearToStringCache()
+ return this
+ }
+
+ override fun toChain(): MessageChain {
+ return this
+ }
+
+ override fun toByteArray(): ByteArray = lazyEncode {
+ stream().forEach { message ->
+ it.write(message.toByteArray())
+ }
+ }
+
+ override fun valueEquals(another: Message): Boolean {
+ if (another !is MessageChain) {
+ return false
+ }
+ return this.list == another.list
+ }
+}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.java
deleted file mode 100644
index c60e0bd83..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.mamoe.mirai.message.defaults;
-
-import net.mamoe.mirai.message.Message;
-
-/**
- * @author Him188moe
- */
-public final class PlainText extends Message {
- private final String text;
-
- public PlainText(String text) {
- this.text = text;
- }
-
- @Override
- public String toString() {
- return text;
- }
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt
new file mode 100644
index 000000000..56506f6fc
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt
@@ -0,0 +1,34 @@
+package net.mamoe.mirai.message.defaults
+
+import net.mamoe.mirai.message.Message
+import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.network.packet.writeVarByteArray
+import net.mamoe.mirai.network.packet.writeVarString
+import net.mamoe.mirai.utils.lazyEncode
+
+/**
+ * @author Him188moe
+ */
+class PlainText(private val text: String) : Message() {
+ override val type: Int = MessageId.TEXT
+
+ override fun toStringImpl(): String {
+ return text
+ }
+
+ override fun toByteArray(): ByteArray = lazyEncode { section ->
+ section.writeByte(this.type)
+
+ section.writeVarByteArray(lazyEncode { child ->
+ child.writeByte(0x01)
+ child.writeVarString(this.text)
+ })
+ }
+
+ override fun valueEquals(another: Message): Boolean {
+ if (another !is PlainText) {
+ return false
+ }
+ return this.text == another.text
+ }
+}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
index c1811de31..4a47a5e7e 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
@@ -14,8 +14,10 @@ import net.mamoe.mirai.event.events.qq.FriendMessageEvent
import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent
import net.mamoe.mirai.event.hookWhile
import net.mamoe.mirai.message.Message
+import net.mamoe.mirai.message.defaults.MessageChain
import net.mamoe.mirai.network.RobotNetworkHandler.*
import net.mamoe.mirai.network.packet.*
+import net.mamoe.mirai.network.packet.action.ClientSendFriendMessagePacket
import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.packet.login.*
@@ -85,16 +87,14 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
//private | internal
- internal fun tryLogin(): CompletableFuture = this.tryLogin(200)//登录回复非常快, 没必要等太久.
-
-
/**
* 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook].
* 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCESS] 调用 [loginHandler]
*
* @param touchingTimeoutMillis 连接每个服务器的 timeout
*/
- internal fun tryLogin(touchingTimeoutMillis: Long): CompletableFuture {
+ @JvmOverloads
+ internal fun tryLogin(touchingTimeoutMillis: Long = 200): CompletableFuture {
val ipQueue: LinkedList = LinkedList(Protocol.SERVER_IP)
val future = CompletableFuture()
@@ -199,10 +199,10 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
return this.loginFuture!!
}
- @Synchronized
/**
* Not async
*/
+ @Synchronized
@ExperimentalUnsignedTypes
internal fun sendPacket(packet: ClientPacket) {
checkNotNull(socket) { "network closed" }
@@ -329,7 +329,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
this.loginIP = packet.loginIP
this.loginTime = packet.loginTime
this.token0825 = packet.token0825
- sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, this.tgtgtKey!!, packet.token0825))
+ sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, this.tgtgtKey, packet.token0825))
}
}
@@ -341,7 +341,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
is ServerVerificationCodeCorrectPacket -> {
this.tgtgtKey = getRandomByteArray(16)
this.token00BA = packet.token00BA
- sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
+ sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey, this.token0825, this.token00BA))
}
is ServerLoginResponseVerificationCodeInitPacket -> {
@@ -419,7 +419,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
//登录成功后会收到大量上次的消息, 忽略掉
MiraiThreadPool.getInstance().schedule({
- (packetHandlers[MessageHandler::class] as MessageHandler).ignoreMessage = false
+ messageHandler.ignoreMessage = false
}, 2, TimeUnit.SECONDS)
this.tlv0105 = packet.tlv0105
@@ -432,7 +432,6 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
}
is ServerSKeyResponsePacket -> {
- val actionHandler = packetHandlers[ActionHandler::class] as ActionHandler
actionHandler.sKey = packet.sKey
actionHandler.cookies = "uin=o" + robot.account.qqNumber + ";skey=" + actionHandler.sKey + ";"
@@ -496,7 +495,12 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
return
}
- FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message)
+ val friendMessageEvent = FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message)
+ friendMessageEvent.broadcast()
+
+ if (friendMessageEvent.message() valueEquals "你好") {
+ friendMessageEvent.qq.sendMessage("你好")
+ }
}
is ServerGroupMessageEventPacket -> {
@@ -515,9 +519,8 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
}
}
- fun sendFriendMessage(qq: QQ, message: Message) {
- TODO()
- //sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message))
+ fun sendFriendMessage(qq: QQ, message: MessageChain) {
+ sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message))
}
fun sendGroupMessage(group: Group, message: Message): Unit {
@@ -532,7 +535,11 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
*/
inner class ActionHandler : PacketHandler() {
internal lateinit var cookies: String
- internal lateinit var sKey: String
+ internal var sKey: String = ""
+ set(value) {
+ field = value
+ gtk = getGTK(value)
+ }
internal var gtk: Int = 0
override fun onPacketReceived(packet: ServerPacket) {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
index c9e3f501a..bea51f94c 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
@@ -230,7 +230,7 @@ fun DataOutputStream.writeZero(count: Int) {
@Throws(IOException::class)
fun DataOutputStream.writeRandom(length: Int) {
repeat(length) {
- this.writeByte((Math.random() * 255).toInt().toByte().toInt())
+ this.writeByte((Math.random() * 255).toInt())
}
}
@@ -244,4 +244,13 @@ fun DataOutputStream.writeQQ(qq: Long) {
@Throws(IOException::class)
fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) {
this.write(groupIdOrGroupNumber.toUInt().toByteArray())
+}
+
+fun DataOutputStream.writeVarByteArray(byteArray: ByteArray) {
+ this.writeShort(byteArray.size)
+ this.write(byteArray)
+}
+
+fun DataOutputStream.writeVarString(str: String) {
+ this.writeVarByteArray(str.toByteArray())
}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
index 2a5c489c9..7bb280023 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
@@ -199,11 +199,10 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
val l1 = input.readShortAt(22)
input.goto(93 + l1)
- val l2 = input.readShort()
- input.readNBytes(l2)//font
+ input.readVarByteArray()//font
input.skip(2)//2个0x00
message = input.readSections()
- println(message.toDebugString())
+ println(message.toObjectString())
/*
val offset = unknownLength0 + fontLength//57
@@ -218,14 +217,14 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
val sectionLength = this.readShort().toLong()//sectionLength: short
this.skip(1)//message和face是 0x01, image是0x06
return when (messageType) {
- 0x01 -> PlainText(readShortVarString())
+ 0x01 -> PlainText(readVarString())
0x02 -> {
//00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0
//00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D
- val id1 = FaceID.ofId(readShortVarNumber().toInt())//可能这个是id, 也可能下面那个
+ val id1 = FaceID.ofId(readVarNumber().toInt())//可能这个是id, 也可能下面那个
this.skip(this.readByte().toLong())
- this.readShortVarNumber()//某id?
+ this.readVarNumber()//某id?
return Face(id1)
}
0x06 -> {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
index e3051f09a..f1811c4c1 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
@@ -176,8 +176,12 @@ fun DataInputStream.readIP(): String {
return buff
}
-fun DataInputStream.readShortVarString(): String {
- return String(this.readNBytes(this.readShort().toInt()))
+fun DataInputStream.readVarString(): String {
+ return String(this.readVarByteArray())
+}
+
+fun DataInputStream.readVarByteArray(): ByteArray {
+ return this.readNBytes(this.readShort().toInt())
}
fun DataInputStream.readString(length: Int): String {
@@ -206,7 +210,7 @@ fun DataInputStream.readNBytes(length: N): ByteArray {
}
-fun DataInputStream.readShortVarNumber(): Number {
+fun DataInputStream.readVarNumber(): Number {
return when (this.readShort().toInt()) {
1 -> this.readByte()
2 -> this.readShort()
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt
index 768993e77..1ac425868 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt
@@ -1,5 +1,6 @@
package net.mamoe.mirai.network.packet.action
+import net.mamoe.mirai.message.defaults.MessageChain
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.utils.lazyEncode
@@ -14,7 +15,7 @@ class ClientSendFriendMessagePacket(
private val robotQQ: Long,
private val targetQQ: Long,
private val sessionKey: ByteArray,
- private val message: String
+ private val message: MessageChain
) : ClientPacket() {
override fun encode() {
this.writeRandom(2)//part of packet id
@@ -36,24 +37,20 @@ class ClientSendFriendMessagePacket(
it.writeTime()
it.writeRandom(4)
it.writeHex("00 00 00 00 09 00 86")
- it.writeHex(Protocol.friendMessageConst1)
+ it.writeHex(Protocol.friendMessageConst1)//... 85 E9 BB 91
it.writeZero(2)
- if ("[face" in message
- || ".gif]" in message
- || ".jpg]" in message
- || ".png]" in message
- ) {
- TODO("复合消息构建")
- } else {
+
+ it.write(message.toByteArray())
+
+ /*
//Plain text
val bytes = message.toByteArray()
it.writeByte(0x01)
it.writeShort(bytes.size + 3)
it.writeByte(0x01)
it.writeShort(bytes.size)
- it.write(bytes)
- }
+ it.write(bytes)*/
}
}
}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt
index 118012401..1a4ed2f70 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt
@@ -29,6 +29,7 @@ object MiraiLogger {
this.print(e.cause.toString())*/
}
+ @Synchronized
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
kotlin.io.println("$color[Mirai] $s : $value")
@@ -52,12 +53,14 @@ infix fun Robot.success(o: Any?) = print(this, o.toString(), LoggerTextFormat.GR
infix fun Robot.debug(o: Any?) = print(this, o.toString(), LoggerTextFormat.YELLOW)
+@Synchronized
private fun print(robot: Robot, value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
kotlin.io.println("$color[Mirai] $s #R${robot.id}: $value")
}
+@Synchronized
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
kotlin.io.println("$color[Mirai] $s : $value")
diff --git a/mirai-ui/pom.xml b/mirai-ui/pom.xml
new file mode 100644
index 000000000..146dd507e
--- /dev/null
+++ b/mirai-ui/pom.xml
@@ -0,0 +1,39 @@
+
+
+ 4.0.0
+
+ mirai-ui
+ 1.0
+
+ jar
+
+
+ net.mamoe
+ mirai
+ 1.0
+ ../pom.xml
+
+
+
+
+
+
+
+
+
+ /src/main/resources
+
+
+ **/*.*
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 28d665c86..7c26ba49b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
mirai-core
mirai-native
+ mirai-ui
@@ -27,41 +28,14 @@
pom
+
+ 1.3.41
11
11
UTF-8
-
- package
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.1
-
-
- org.ow2.asm
- asm
- 7.1
-
-
-
- UTF-8
-
-
-
-
- org.projectlombok
- lombok-maven-plugin
- 1.18.6.0
-
-
-
-
-
@@ -121,7 +95,114 @@
0.5.2
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${kotlin.version}
+
+
+
+
+ org.apache.logging.log4j
+ log4j-core
+ 2.12.1
+
+
+
+ org.yaml
+ snakeyaml
+ 1.18
+
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ 1.3.41
+ compile
+
+
+
+ package
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ org.ow2.asm
+ asm
+ 7.1
+
+
+
+ UTF-8
+
+
+
+
+ org.projectlombok
+ lombok-maven-plugin
+ 1.18.6.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.4.3
+
+
+ package
+
+ shade
+
+
+
+
+ true
+ shaded
+
+
+
+
+ org.projectlombok
+ lombok-maven-plugin
+ 1.18.6.0
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+ compile
+ process-sources
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+ 1.8
+
+
+
+
+
+
\ No newline at end of file