mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-06 06:46:59 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
d05cecefc5
BIN
.README_images/68f8fec9.png
Normal file
BIN
.README_images/68f8fec9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
BIN
.github/A}YWVE860U(%YQD$R1GB1[P.png
vendored
Normal file
BIN
.github/A}YWVE860U(%YQD$R1GB1[P.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
.github/J]CE)IK4BU08(EO~UVLJ{[F.png
vendored
Normal file
BIN
.github/J]CE)IK4BU08(EO~UVLJ{[F.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
BIN
.github/event hook.png
vendored
Normal file
BIN
.github/event hook.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
55
README.md
55
README.md
@ -3,37 +3,48 @@
|
|||||||
一个以<b>TIM QQ协议</b>驱动的JAVA(+Kotlin) QQ机器人服务端核心
|
一个以<b>TIM QQ协议</b>驱动的JAVA(+Kotlin) QQ机器人服务端核心
|
||||||
我们坚持免费与开源
|
我们坚持免费与开源
|
||||||
|
|
||||||
项目处于快速开发阶段, 现在已经可以接受和发送群聊/好友消息.
|
项目处于快速开发阶段
|
||||||
协议来自网络上开源项目
|
协议来自网络上开源项目
|
||||||
一切开发旨在学习, 请勿用于非法用途
|
一切开发旨在学习, 请勿用于非法用途
|
||||||
|
|
||||||
<br>
|
### 抢先体验
|
||||||
|
现在你可以使用 Mirai 内置的一些测试qq号体验 Mirai, 但我们现在还不建议你使用自己的 qq 号登录
|
||||||
|
1. Clone
|
||||||
|
2. Import as Maven project
|
||||||
|
3. Run [MiraiMain](mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java#L7)
|
||||||
|
|
||||||
A JAVA(+Kotlin) powered open-source project under GPL license<br>
|
#### 事件 Hook (Kotlin)
|
||||||
It use protocols from <i>TIM QQ</i>, that is, it won't be affected by the close of <i>Smart QQ</i><br>
|
![event hook.png](.github/event%20hook.png)
|
||||||
The project is all for <b>learning proposes</b> and still in <b>developing stage</b><br>
|
![AYWVE86P](.github/A%7DYWVE860U%28%25YQD%24R1GB1%5BP.png)
|
||||||
|
|
||||||
|
#### 图片测试
|
||||||
|
**现在可以接受图片消息**(并解析为消息链):
|
||||||
|
![JsssF](.github/J%5DCE%29IK4BU08%28EO~UVLJ%7B%5BF.png)
|
||||||
|
![](.README_images/68f8fec9.png)
|
||||||
|
|
||||||
|
不过我们还正在努力做发送图片
|
||||||
|
|
||||||
### 代码结构
|
### 代码结构
|
||||||
Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
|
Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
|
||||||
与插件相关性强(或其他在二次开发中容易接触)的部分使用 Java 完成,
|
与插件相关性强(或其他在二次开发中容易接触)的部分尽量使用 Java 完成,
|
||||||
同时也会针对kotlin提供优化的方法调用. 例如对'+'操作符的重载: `String+BufferedImage+QQ.At+Face+URL+String+File` 将会被自动处理为String消息.
|
若使用 Kotlin, 我们会通过 Java interface 实现或 javadoc 帮助未接触过 Kotlin 的开发者.
|
||||||
|
即使你完全不了解 Kotlin, 你也可以正常开发.
|
||||||
|
|
||||||
|
## TODO
|
||||||
### TODO
|
|
||||||
- [x] 事件(Event)模块
|
- [x] 事件(Event)模块
|
||||||
- [ ] 插件(Plugin)模块
|
- [ ] 插件(Plugin)模块 **(Working on)**
|
||||||
- [x] Network - Touch
|
- [x] Network - Touch
|
||||||
- [X] Network - Login
|
- [X] Network - Login
|
||||||
- [X] Network - Session
|
- [X] Network - Session
|
||||||
- [ ] Network - Verification Code **(Working on)**
|
- [X] Network - Verification Code
|
||||||
- [X] Network - Message Receiving
|
- [X] Network - Message Receiving
|
||||||
- [X] Network - Message Sending
|
- [X] Network - Message Sending
|
||||||
- [ ] Network - Events **(Working on)**
|
- [ ] Network - Events **(Working on)**
|
||||||
- [ ] Robot - Friend/group list
|
- [ ] Bot - Friend/group list
|
||||||
- [ ] Robot - Actions(joining group, adding friend, etc.)
|
- [ ] Bot - Actions(joining group, adding friend, etc.)
|
||||||
- [ ] Message Section **(Working on)**
|
- [ ] Message Section **(Working on)**
|
||||||
- [ ] Contact
|
- [ ] Contact
|
||||||
- [ ] UI **(Working on)**
|
- [ ] UI
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@ -42,18 +53,24 @@ Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
|
|||||||
- Java 11 或更高
|
- Java 11 或更高
|
||||||
- Kotlin 1.3 或更高
|
- Kotlin 1.3 或更高
|
||||||
### 插件开发
|
### 插件开发
|
||||||
``` php
|
``` text
|
||||||
to be continued
|
to be continued
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
A JAVA(+Kotlin) powered open-source project under GPL license<br>
|
||||||
|
It use protocols from <i>TIM QQ</i>, that is, it won't be affected by the close of <i>Smart QQ</i><br>
|
||||||
|
The project is all for <b>learning proposes</b> and still in <b>developing stage</b><br>
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
### Requirements
|
### Requirements
|
||||||
- Java 11 or higher
|
- Java 11 or higher
|
||||||
- Kotlin 1.3 or higher
|
- Kotlin 1.3 or higher
|
||||||
### Plugin Development
|
### Plugin Development
|
||||||
``` php
|
``` text
|
||||||
to be continued
|
to be continued
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
g_count = 0
|
|
||||||
paccket sent: 02 37 13 08 25 31 01 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D 9F A7 43 90 2A 9D 29 B5 EA DB 50 7F D3 78 1C AE 31 7E 7E 4F A9 1B B5 C9 8D A8 4C 78 98 13 E1 45 FC 35 2E 22 3D E0 39 1A 3F C6 8B CA 06 A8 F3 B3 6F 95 D8 64 1A B0 E9 29 06 DB 5C F4 9B 32 47 5A B7 10 57 C5 2F C9 D9 7B 17 22 7F 09 A6 8C 30 04 24 0F 1D 61 A1 42 E2 7A AA 15 36 AC 67 9B 7A 4D 42 14 AD F5 2D D2 A3 CA 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 08 25 31 01
|
|
||||||
DataArrived >> dispose_0825 >>
|
|
||||||
DataArrived >> dispose_0825 >> redirect
|
|
||||||
DataArrived >> dispose_0825 >> g_server = 125.39.132.167
|
|
||||||
DataArrived >> dispose_0825 >> g_count = 0
|
|
||||||
DataArrived >> dispose_0825 >> paccket sent: 02 37 13 08 25 31 02 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B 23 89 DB A3 07 80 49 63 01 76 69 F1 E1 11 32 06 E9 7F E4 6A 6B 98 07 75 EF 0E 1F 81 10 85 86 EB 96 8E 65 78 0F C3 BC F8 FF 51 3E 36 4F 48 3C 78 52 26 3F 4C 20 65 85 69 AC B8 36 B6 50 50 CC 01 4A 35 44 15 5C 80 B9 F7 A7 56 D4 B2 D4 A4 D9 09 56 29 93 39 0C C8 9C 0B F7 2D CE BE B0 D5 4C CE 48 B3 2D 18 28 A2 3C DD 26 C1 F1 6E A1 4B EC 8A 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 08 25 31 02
|
|
||||||
DataArrived >> dispose_0825 >>
|
|
||||||
DataArrived >> dispose_0825 >> g_count = 0
|
|
||||||
DataArrived >> dispose_0825 >> 不需要redirect
|
|
||||||
DataArrived >> dispose_0825 >> m_loginTime = 5D 59 7D A6
|
|
||||||
DataArrived >> dispose_0825 >> m_loginIP = B7 5F F8 D4
|
|
||||||
DataArrived >> dispose_0825 >> m_0825token = 16 5A 4A C4 FE D1 F8 A3 CB B7 37 DD A5 AE 5C F7 04 74 36 91 4E CD 4A E6 EF 43 31 A7 D1 97 CC 6B 93 C7 9B 15 62 FD 11 3E 19 E1 69 62 B3 BC F4 9A E1 17 19 47 CC A3 1E AC
|
|
||||||
DataArrived >> dispose_0825 >> m_tgtgtKey = DB DE AE DD C7 ED 35 B6 DD 2B 71 6B C4 14 C6 6B
|
|
||||||
DataArrived >> dispose_0825 >> g_count = 0
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >>
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> PCName = DESKTOP-M17JREU
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> PCName = 44 45 53 4B 54 4F 50 2D 4D 31 37 4A 52 45 55
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> g_pass = xiaoqqq
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> g_QQ = 76 E4 B8 DD
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> crc32_code(Random) = 0C 69 01 0E FF CE E7 78 BA CA C7 66 AF 7B 07 22
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> crc32_data = 8B D9 F6 A1
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> getTLV0006 >>
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> getTLV0006 >> m_tgtgtKey = DB DE AE DD C7 ED 35 B6 DD 2B 71 6B C4 14 C6 6B
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> getTLV0006 >> packet = A9 4E DF FB 00 02 76 E4 B8 DD 00 00 04 53 00 00 00 01 00 00 15 85 00 00 01 95 5B 96 CB 95 CF 1C A6 94 C4 B7 79 07 9A BB 15 5D 59 7D A6 00 00 00 00 00 00 00 00 00 00 00 00 00 B7 5F F8 D4 00 00 00 00 00 00 00 00 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B DB DE AE DD C7 ED 35 B6 DD 2B 71 6B C4 14 C6 6B
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >>
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> PCName = DESKTOP-M17JREU
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> PCName = 44 45 53 4B 54 4F 50 2D 4D 31 37 4A 52 45 55
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> g_pass = xiaoqqq
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> g_QQ = 76 E4 B8 DD
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> crc32_code(Random) = 1B A6 09 08 3C CB 94 A1 9D 76 2C A0 B7 AC 98 44
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> crc32_data = 57 4F 04 4B
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> getTLV0006 >>
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> getTLV0006 >> m_tgtgtKey = DB DE AE DD C7 ED 35 B6 DD 2B 71 6B C4 14 C6 6B
|
|
||||||
DataArrived >> dispose_0825 >> Construct_0836_622 >> getTLV0006 >> packet = 7F E3 7A 1F 00 02 76 E4 B8 DD 00 00 04 53 00 00 00 01 00 00 15 85 00 00 01 95 5B 96 CB 95 CF 1C A6 94 C4 B7 79 07 9A BB 15 5D 59 7D A6 00 00 00 00 00 00 00 00 00 00 00 00 00 B7 5F F8 D4 00 00 00 00 00 00 00 00 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B DB DE AE DD C7 ED 35 B6 DD 2B 71 6B C4 14 C6 6B
|
|
||||||
DataArrived >> dispose_0825 >> paccket sent: 02 37 13 08 36 31 03 76 E4 B8 DD 03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19 02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3 00 00 00 10 EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA 12 58 AF 79 C5 60 54 5F A9 30 38 87 E9 B0 68 FA D3 83 A7 6A EA B6 7F 54 10 78 F0 47 60 24 1B E2 91 2D FD 60 F4 C7 DE 3C 7C 56 83 BE B4 66 49 60 5F E0 D3 2B 18 BD 5D 64 28 D1 98 8F 83 84 98 03 97 DE 97 83 5A BD 0B AC 1B 63 7C A2 C8 13 C2 26 8A C1 AA 6D B8 5D 4A 91 E7 C8 7B AF 3C 89 76 DF EA F3 F3 53 AD 69 2F 4C 45 90 69 B7 69 3E 05 C9 DE 1B B1 C9 DE D3 F6 4B 70 3D 27 54 BC D6 2B AB 68 13 2D E7 E3 11 FF 98 3F 1E 51 BC D6 F5 AB 26 DA 53 82 7B 3C 23 99 D8 77 95 32 64 C9 11 C5 8D 40 EA F6 E7 84 C6 B0 94 EE 4A 7E 22 1E 30 34 59 AB D1 66 79 EA A5 D4 AD A2 7D 4D 47 B8 FC 86 BC DD 5D 27 15 94 E0 1B 68 00 DD 5E 5A 09 08 E0 F5 91 EF 98 95 CC 92 B9 A0 EB AC 62 B5 5D DD AA EC 4F 36 48 6E C9 7C 2D 1F 21 98 F5 27 28 E5 8E 4A 51 BC 9A 2A BE 50 31 21 EC DF C8 97 35 58 76 B3 CD F9 92 7A 86 0E C4 1D 90 62 86 99 20 92 6C 12 C9 E2 E9 7F 0B 6B AC 59 00 55 7E B6 45 B1 C4 01 37 A6 1D B3 6E 16 06 96 40 59 CD 59 5D 6F 96 E9 B4 97 0D 55 AE 3B BF FA 54 73 D3 06 B3 47 AA 7E A1 89 F5 04 79 62 7C 11 B4 1C 4D F7 24 92 71 42 17 DC 52 67 9C 66 97 5F 64 1D CD 35 68 7D D5 D7 51 9B BA 29 92 E7 8B 6F B4 74 9E 84 54 5F E8 0D 81 89 15 FB 30 A0 1B AD B2 A3 46 3F F1 A7 A7 A1 A2 A6 D1 7D B0 4E D4 E9 87 AA 20 ED 9A 04 22 5F 57 45 20 05 2B 48 CD 06 4B BC 6F F2 92 D5 09 07 DF 83 DA FC 9D 75 50 C3 75 98 56 8C B3 B0 02 80 FD ED 61 03 00 86 EA E1 03 D2 08 68 B4 1F B9 9C EB 7B 75 9C 2D 94 10 F1 C0 40 E8 D9 9A DB 4A 0F 42 90 78 F6 AB 5B 7D 5A 18 ED 3F 45 8E 1F 98 D0 97 79 51 1D 2D 64 23 8D 30 93 FF C1 B2 05 1D 22 0C E6 51 CD F3 D5 F6 D9 DB 31 EC B2 2F B1 D1 ED F3 54 5F B3 F9 B9 74 0B 10 21 4D 84 52 CD 61 A2 39 51 CD 38 AF 2B DD BD CC 70 76 31 76 51 49 B7 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 08 36 31 03
|
|
||||||
DataArrived >> Dispose_0836 >>
|
|
||||||
DataArrived >> Dispose_0836 >> m_0828_rec_decr_key = 37 61 4D 6D 48 73 77 6D 38 70 4B 23 6D 5F 21 5F
|
|
||||||
DataArrived >> Dispose_0836 >> nick_length = 20
|
|
||||||
DataArrived >> Dispose_0836 >> m_nick = (?ω)
|
|
||||||
DataArrived >> Dispose_0836 >> m_age = 5
|
|
||||||
DataArrived >> Dispose_0836 >> m_gender = 02
|
|
||||||
DataArrived >> Dispose_0836 >> g_clientKey = 00015D597DA60068666D5741D077D580228800B480E93195D2165593A44A6D42D81D38AC1A1E914F89D0B9FC15DFADB2D7257DF2B15D90FB2F6B4B9CF0EE4C38C9556C8FFCA43E688FD0CEE570350500A626547C4A76CFAF7586AC1B2CE400A93F9384FF7037B11FD5602EFAE870CD0F
|
|
||||||
DataArrived >> Dispose_0836 >> token38 = BA 24 BF EA 76 94 2C 9B 91 A8 8F 0E 7C EC F5 41 77 3C B9 D4 95 50 F2 00 FD CB E3 48 36 FB 89 13 CE E4 EA 76 A2 2F 20 86 F6 0F E0 54 55 6E D4 0B 9B EA 07 6B E1 D4 87 56
|
|
||||||
DataArrived >> Dispose_0836 >> token88 = 00 04 5D 59 7D A6 B7 5F F8 D4 00 00 00 00 00 78 AA 32 D3 89 86 C9 B0 41 6F 37 4F 2C 51 BA EC 9A C7 38 05 91 5C D9 3E 13 FC 5F E7 77 D0 A1 E8 B3 40 E3 3E 4E 27 B8 C2 0E F9 62 67 FA 65 E1 C9 DB F3 0B A5 F0 4B 13 7A B6 EA 1D 3C AD 8C 34 D4 3B FD 75 0C FE F5 4B 28 33 76 57 AA 68 F9 94 E1 72 41 D1 9C E5 D4 7C C6 2C 25 C5 07 A5 42 95 51 2F E0 88 41 DE 3E 9D 4F 4D 70 32 5E 44 28 5C 88 DA A6 8F 13 2B 79 C8 93 1D
|
|
||||||
DataArrived >> Dispose_0836 >> encryptionKey = C9 E2 F2 CB 45 79 DE F7 6C 51 7C 9B 97 CC D0 47
|
|
||||||
DataArrived >> Dispose_0836 >> g_count = 0
|
|
||||||
DataArrived >> Dispose_0836 >> Construct_0828 >>
|
|
||||||
DataArrived >> Dispose_0836 >> paccket sent: 02 37 13 08 28 04 34 76 E4 B8 DD 02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A 00 38 BA 24 BF EA 76 94 2C 9B 91 A8 8F 0E 7C EC F5 41 77 3C B9 D4 95 50 F2 00 FD CB E3 48 36 FB 89 13 CE E4 EA 76 A2 2F 20 86 F6 0F E0 54 55 6E D4 0B 9B EA 07 6B E1 D4 87 56 F9 99 8F FA 12 8E 22 A6 5A 9D A6 DC C9 B6 5C 5A EC BE BF CC 38 BD E1 5A 23 21 CE 02 31 F1 E1 BD FB 8E 4D E9 59 E6 BB FB B2 36 0C 47 0A C0 F7 94 63 C3 2F AB 6E AE 00 01 1F 5F 60 8E B5 79 97 EB 10 59 A0 29 B3 3B 9C BA 5D 33 C4 2A 57 CA CF 94 7A 2D DD F7 B3 9C BC 65 5D D5 62 53 A8 1D D2 F1 5B DD D7 24 32 63 60 60 DD 33 1F 3A C0 71 38 86 BC 78 D3 7C 7A E1 97 71 AB B7 59 AD 27 32 D5 AF F3 DC 1B 7B 70 3B 08 C0 91 D8 BC F1 C4 DA E3 DA 86 A1 27 8A EE C3 5F D6 25 42 A0 CB 19 7F 08 80 F8 65 2C 27 31 B7 D4 85 C3 49 BD 99 48 FE A9 63 78 6D 18 C3 4E BB F7 8A C4 80 8C 8A 17 EB 47 AF 2A 12 73 71 08 A6 E7 C3 08 2B 9A 6F 8A C2 6C 3B 1A CF 05 D8 57 63 33 AC BD 45 98 C1 85 56 08 0F 9F 36 FD 60 69 BC D0 94 1A 11 4D C6 3E 78 1D F1 67 D2 1D C4 C8 17 2F DC F4 B6 4F 5F F5 EE 8B 73 68 AA 3B BA C6 94 C8 21 1E 95 6D C2 7A BE 8B 1D 92 21 8D 2C D8 B6 86 D1 30 BB 72 34 B9 A0 D2 2E 4C 98 3C 17 E2 B2 6A AD 75 E8 B0 DE F4 1A 6F 15 93 47 B3 4D DA 6F BE A3 47 D3 9B 58 2D 4B A3 76 0E 39 ED A5 C3 0A 34 BA 78 01 AE 20 A3 38 CE BA CD F6 D7 1B C9 E7 4C 83 6E 31 34 25 16 64 BA EE 4B 8D E7 0E 2F C8 08 72 50 AE 91 16 7F 68 14 60 7E D8 3F CC 26 2D F6 BC 65 72 C8 F4 EA 55 E6 1B E0 BF F4 9F 9C FD A9 93 B6 62 78 F0 A1 19 D2 87 6E B8 B7 E3 70 13 09 95 29 C9 05 EC 99 36 5C 96 47 C1 C4 06 5C 23 5C A3 AD B0 39 BC 70 75 3D AA E9 16 03 0E 62 1B D0 78 EA F2 5C FD 9C 04 D9 AB 75 00 F8 37 F1 A8 DD 7B 65 91 D3 58 DE C5 BA 9E AC 13 DE 35 BA 17 DC D1 AB A5 96 C4 99 81 8E 21 4B 2F C1 9B 4C E1 56 A7 5D AC 26 71 EC 49 F0 A6 B1 F5 43 EA AC BE E6 9F A0 C2 E1 68 35 97 7B 81 76 AF 9E BD BC A7 D8 9E FC C0 E8 21 B0 BA 20 6A D0 BD E7 00 59 06 61 A1 DF AA 9F BA F4 5D A6 7B 5B A1 D8 6B B5 E9 72 66 51 8A D3 CE 51 A9 08 C7 11 4B FB 29 2E 6C 48 5B 8A 50 C6 5D 3A C1 9E A1 51 B6 56 DD 6B F5 D2 FD AE AB A4 4A A8 1F 99 BA 7D 4F 62 D7 64 22 31 04 62 36 62 65 96 B3 5A 35 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 08 28 04 34
|
|
||||||
DataArrived >> Dispose_0828 >>
|
|
||||||
DataArrived >> Dispose_0828 >> g_count = 0
|
|
||||||
DataArrived >> Dispose_0828 >> g_sessionKey = D1 ED 7E 0B 6B BC 6F F0 2C 7E 31 8F 58 49 6D 20
|
|
||||||
DataArrived >> Dispose_0828 >> g_tlv0105 = 01 05 00 88 00 01 01 02 00 40 02 01 03 3C 01 03 00 00 C2 D9 3F A5 A0 1B 6C 03 A2 EF AB CB 42 92 44 8E 15 97 28 1F DE B6 E9 0A 5C 53 01 CE A2 CC 95 3F E0 CB 30 3F 5C 67 09 22 83 CC 8A 80 8F D6 26 F5 EF EC 24 15 95 8E CE 99 00 40 02 02 03 3C 01 03 00 00 A1 4D 57 52 9E 5B 1F BB 48 75 09 67 F8 C0 64 F6 9B 2A 44 61 78 29 C1 26 9C 3C 59 0E DF 9B D1 59 97 0B 0C 2B 09 27 C6 7C 20 63 11 02 E1 4E A4 DE E2 59 CF A7 A1 47 0A B6
|
|
||||||
DataArrived >> Dispose_0828 >> g_loginStatus = 0A
|
|
||||||
DataArrived >> Dispose_0828 >> paccket sent: 02 37 13 00 EC 6E 8E 76 E4 B8 DD 02 00 00 00 01 01 01 00 00 68 20 C4 28 24 D6 67 13 CE 5F F7 F8 38 79 F4 56 1F CA 13 95 22 4D 7B 5D B6 59 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 00 EC 6E 8E
|
|
||||||
DataArrived >> g_count = 0
|
|
||||||
DataArrived >> paccket sent: 02 37 13 00 1D C5 CB 76 E4 B8 DD 02 00 00 00 01 01 01 00 00 68 20 F3 B2 B9 BF F9 C9 87 EB C2 33 FD BA 6B 16 44 E8 B2 C1 8C 7E 4F 97 01 13 88 D8 00 BF 5F 6C 38 22 E0 50 4F 9B 73 7F 5F 31 64 72 9A C1 11 79 F5 B9 33 C0 EC 81 5E F7 D5 A4 BF C6 29 9F 18 9E C0 99 CE B7 16 E5 E8 BF EE E7 5A C3 5C 28 68 3E 48 18 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 00 1D C5 CB
|
|
||||||
DataArrived >> paccket sent: 02 37 13 00 5C 7B 2E 76 E4 B8 DD 02 00 00 00 01 01 01 00 00 68 20 E7 E2 64 22 9C 2F 33 27 A3 8B 4D 9C DE C5 A8 0D 03
|
|
||||||
DataArrived >>
|
|
||||||
DataArrived >> flag = 00 5C 7B 2E
|
|
37
mirai-api/pom.xml
Normal file
37
mirai-api/pom.xml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.mamoe</groupId>
|
||||||
|
<artifactId>mirai</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>mirai-api</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>/src/main/resources</directory>
|
||||||
|
|
||||||
|
<includes>
|
||||||
|
<include>**/*.*</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
37
mirai-console/pom.xml
Normal file
37
mirai-console/pom.xml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.mamoe</groupId>
|
||||||
|
<artifactId>mirai</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>mirai-console</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>/src/main/resources</directory>
|
||||||
|
|
||||||
|
<includes>
|
||||||
|
<include>**/*.*</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -9,10 +9,6 @@
|
|||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<kotlin.version>1.3.41</kotlin.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>net.mamoe</groupId>
|
<groupId>net.mamoe</groupId>
|
||||||
<artifactId>mirai</artifactId>
|
<artifactId>mirai</artifactId>
|
||||||
@ -21,7 +17,6 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
<groupId>org.jetbrains.kotlinx</groupId>
|
||||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||||
@ -31,42 +26,36 @@
|
|||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-all</artifactId>
|
<artifactId>netty-all</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.java.dev.jna</groupId>
|
<groupId>net.java.dev.jna</groupId>
|
||||||
<artifactId>jna</artifactId>
|
<artifactId>jna</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-stdlib</artifactId>
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
<version>${kotlin.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
<version>2.12.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<version>1.18</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.yaml</groupId>
|
|
||||||
<artifactId>snakeyaml</artifactId>
|
|
||||||
<version>1.18</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-reflect</artifactId>
|
<artifactId>kotlin-reflect</artifactId>
|
||||||
<version>1.3.41</version>
|
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>/src/main/resources</directory>
|
<directory>/src/main/resources</directory>
|
||||||
@ -94,63 +83,16 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.4.3</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
|
||||||
<shadedClassifierName>shaded</shadedClassifierName>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-maven-plugin</artifactId>
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
<version>${kotlin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>compile</id>
|
|
||||||
<phase>process-sources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>compile</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>test-compile</id>
|
|
||||||
<phase>test-compile</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>test-compile</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<jvmTarget>1.8</jvmTarget>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>compile</id>
|
|
||||||
<phase>compile</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>compile</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>testCompile</id>
|
|
||||||
<phase>test-compile</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>testCompile</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
@ -3,47 +3,59 @@ package net.mamoe.mirai;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.mamoe.mirai.contact.Group;
|
import net.mamoe.mirai.contact.Group;
|
||||||
import net.mamoe.mirai.contact.QQ;
|
import net.mamoe.mirai.contact.QQ;
|
||||||
import net.mamoe.mirai.network.RobotNetworkHandler;
|
import net.mamoe.mirai.network.BotNetworkHandler;
|
||||||
|
import net.mamoe.mirai.utils.BotAccount;
|
||||||
import net.mamoe.mirai.utils.ContactList;
|
import net.mamoe.mirai.utils.ContactList;
|
||||||
import net.mamoe.mirai.utils.RobotAccount;
|
|
||||||
import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirai 的机器人. 一个机器人实例登录一个 QQ 账号.
|
* Mirai 的机器人. 一个机器人实例登录一个 QQ 账号.
|
||||||
* Mirai 为多账号设计, 可同时维护多个机器人账号.
|
* Mirai 为多账号设计, 可同时维护多个机器人.
|
||||||
* <br>
|
* <br>
|
||||||
* {@link Robot} 由 2 个模块组成.
|
* {@link Bot} 由 2 个模块组成.
|
||||||
* {@linkplain ContactSystem 联系人管理}: 可通过 {@link Robot#contacts} 访问
|
* {@linkplain ContactSystem 联系人管理}: 可通过 {@link Bot#contacts} 访问
|
||||||
* {@linkplain RobotNetworkHandler 网络处理器}: 可通过 {@link Robot#network} 访问
|
* {@linkplain BotNetworkHandler 网络处理器}: 可通过 {@link Bot#network} 访问
|
||||||
* <br>
|
* <br>
|
||||||
* 另外地, 若你需要得到机器人的 QQ 账号, 请访问 {@link Robot#account}
|
* 若你需要得到机器人的 QQ 账号, 请访问 {@link Bot#account}
|
||||||
* 若你需要得到服务器上所有机器人列表, 请访问 {@link Robot#instances}
|
* 若你需要得到服务器上所有机器人列表, 请访问 {@link Bot#instances}
|
||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
* @author NatrualHG
|
* @author NatrualHG
|
||||||
* @see net.mamoe.mirai.contact.Contact
|
* @see net.mamoe.mirai.contact.Contact
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Robot that is the base of the whole program.
|
* Bot that is the base of the whole program.
|
||||||
* It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}.
|
* It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}.
|
||||||
*/
|
*/
|
||||||
public final class Robot implements Closeable {
|
public final class Bot implements Closeable {
|
||||||
public static final List<Robot> instances = Collections.synchronizedList(new LinkedList<>());
|
public static final List<Bot> instances = Collections.synchronizedList(new LinkedList<>());
|
||||||
|
|
||||||
public final RobotAccount account;
|
{
|
||||||
|
instances.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int id = _id.getAndAdd(1);
|
||||||
|
|
||||||
|
public final BotAccount account;
|
||||||
|
|
||||||
public final ContactSystem contacts = new ContactSystem();
|
public final ContactSystem contacts = new ContactSystem();
|
||||||
|
|
||||||
public final RobotNetworkHandler network;
|
public final BotNetworkHandler network;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Bot{id=%d,qq=%d}", id, this.account.qqNumber);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Robot 联系人管理.
|
* Bot 联系人管理.
|
||||||
*
|
*
|
||||||
* @see Robot#contacts
|
* @see Bot#contacts
|
||||||
*/
|
*/
|
||||||
public final class ContactSystem {
|
public final class ContactSystem {
|
||||||
private final ContactList<Group> groups = new ContactList<>();
|
private final ContactList<Group> groups = new ContactList<>();
|
||||||
@ -55,14 +67,14 @@ public final class Robot implements Closeable {
|
|||||||
|
|
||||||
public QQ getQQ(long qqNumber) {
|
public QQ getQQ(long qqNumber) {
|
||||||
if (!this.qqs.containsKey(qqNumber)) {
|
if (!this.qqs.containsKey(qqNumber)) {
|
||||||
this.qqs.put(qqNumber, new QQ(Robot.this, qqNumber));
|
this.qqs.put(qqNumber, new QQ(Bot.this, qqNumber));
|
||||||
}
|
}
|
||||||
return this.qqs.get(qqNumber);
|
return this.qqs.get(qqNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Group getGroupByNumber(long groupNumber) {
|
public Group getGroupByNumber(long groupNumber) {
|
||||||
if (!this.groups.containsKey(groupNumber)) {
|
if (!this.groups.containsKey(groupNumber)) {
|
||||||
this.groups.put(groupNumber, new Group(Robot.this, groupNumber));
|
this.groups.put(groupNumber, new Group(Bot.this, groupNumber));
|
||||||
}
|
}
|
||||||
return groups.get(groupNumber);
|
return groups.get(groupNumber);
|
||||||
}
|
}
|
||||||
@ -83,9 +95,9 @@ public final class Robot implements Closeable {
|
|||||||
return owners.contains(ownerName);
|
return owners.contains(ownerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Robot(MiraiConfigSection<Object> data) throws Throwable {
|
public Bot(MiraiConfigSection<Object> data) throws Throwable {
|
||||||
this(
|
this(
|
||||||
new RobotAccount(
|
new BotAccount(
|
||||||
data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
|
data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
|
||||||
data.getStringOrThrow("password", () -> new IllegalArgumentException("password"))
|
data.getStringOrThrow("password", () -> new IllegalArgumentException("password"))
|
||||||
),
|
),
|
||||||
@ -93,12 +105,12 @@ public final class Robot implements Closeable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Robot(@NotNull RobotAccount account, @NotNull List<String> owners) {
|
public Bot(@NotNull BotAccount account, @NotNull List<String> owners) {
|
||||||
Objects.requireNonNull(account);
|
Objects.requireNonNull(account);
|
||||||
Objects.requireNonNull(owners);
|
Objects.requireNonNull(owners);
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.owners = Collections.unmodifiableList(owners);
|
this.owners = Collections.unmodifiableList(owners);
|
||||||
this.network = new RobotNetworkHandler(this);
|
this.network = new BotNetworkHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -109,5 +121,12 @@ public final class Robot implements Closeable {
|
|||||||
this.contacts.qqs.clear();
|
this.contacts.qqs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addFriend(long qq) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PRIVATE */
|
||||||
|
|
||||||
|
private static final AtomicInteger _id = new AtomicInteger(0);
|
||||||
}
|
}
|
||||||
|
|
@ -6,8 +6,10 @@ import net.mamoe.mirai.event.events.server.ServerDisabledEvent;
|
|||||||
import net.mamoe.mirai.event.events.server.ServerEnabledEvent;
|
import net.mamoe.mirai.event.events.server.ServerEnabledEvent;
|
||||||
import net.mamoe.mirai.network.packet.login.LoginState;
|
import net.mamoe.mirai.network.packet.login.LoginState;
|
||||||
import net.mamoe.mirai.task.MiraiTaskManager;
|
import net.mamoe.mirai.task.MiraiTaskManager;
|
||||||
|
import net.mamoe.mirai.utils.BotAccount;
|
||||||
import net.mamoe.mirai.utils.LoggerTextFormat;
|
import net.mamoe.mirai.utils.LoggerTextFormat;
|
||||||
import net.mamoe.mirai.utils.MiraiLogger;
|
import net.mamoe.mirai.utils.MiraiLogger;
|
||||||
|
import net.mamoe.mirai.utils.MiraiLoggerKt;
|
||||||
import net.mamoe.mirai.utils.config.MiraiConfig;
|
import net.mamoe.mirai.utils.config.MiraiConfig;
|
||||||
import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
||||||
import net.mamoe.mirai.utils.setting.MiraiSettingListSection;
|
import net.mamoe.mirai.utils.setting.MiraiSettingListSection;
|
||||||
@ -16,7 +18,9 @@ import net.mamoe.mirai.utils.setting.MiraiSettings;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author NaturalHG
|
* @author NaturalHG
|
||||||
@ -150,9 +154,8 @@ public class MiraiServer {
|
|||||||
|
|
||||||
MiraiConfigSection<Object> section = new MiraiConfigSection<>();
|
MiraiConfigSection<Object> section = new MiraiConfigSection<>();
|
||||||
|
|
||||||
System.out.println("/");
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
Scanner scanner = new Scanner(System.in);
|
||||||
getLogger().info("Input a " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.GREEN + "for default robotNetworkHandler");
|
getLogger().info("Input a " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.GREEN + "for default botNetworkHandler");
|
||||||
getLogger().info("输入用于默认机器人的QQ号");
|
getLogger().info("输入用于默认机器人的QQ号");
|
||||||
long qqNumber = scanner.nextLong();
|
long qqNumber = scanner.nextLong();
|
||||||
getLogger().info("Input the password for that QQ account");
|
getLogger().info("Input the password for that QQ account");
|
||||||
@ -173,30 +176,60 @@ public class MiraiServer {
|
|||||||
getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai");
|
getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai");
|
||||||
getLogger().info("Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION);
|
getLogger().info("Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION);
|
||||||
|
|
||||||
getLogger().info("Initializing [Robot]s");
|
getLogger().info("Initializing [Bot]s");
|
||||||
|
|
||||||
|
try {
|
||||||
|
getAvailableBot();
|
||||||
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
|
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
|
||||||
getLogger().info("Initializing [Robot] " + section.getString("account"));
|
getLogger().info("Initializing [Bot] " + section.getString("account"));
|
||||||
try {
|
try {
|
||||||
Robot robot = new Robot(section);
|
Bot bot = new Bot(section);
|
||||||
var state = robot.network.tryLogin$mirai_core().get();
|
var state = bot.network.tryLogin$mirai_core().get();
|
||||||
//robot.network.tryLogin$mirai_core().whenComplete((state, e) -> {
|
//bot.network.tryLogin$mirai_core().whenComplete((state, e) -> {
|
||||||
if (state == LoginState.SUCCEED) {
|
if (state == LoginState.SUCCESS) {
|
||||||
Robot.instances.add(robot);
|
Bot.instances.add(bot);
|
||||||
getLogger().success(" Login Succeed");
|
getLogger().success(" Login Succeed");
|
||||||
} else {
|
} else {
|
||||||
getLogger().error(" Login Failed with error " + state);
|
getLogger().error(" Login Failed with error " + state);
|
||||||
robot.close();
|
bot.close();
|
||||||
}
|
}
|
||||||
// }).get();
|
// }).get();
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
getLogger().error("Could not load QQ robots config!");
|
getLogger().error("Could not load QQ bots config!");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String qqList = "3150499752----1234567890\n" +
|
||||||
|
"3119292829----987654321\n" +
|
||||||
|
"2399148773----12345678910\n" +
|
||||||
|
"3145561616----987654321\n" +
|
||||||
|
"2374150554----12345678910\n" +
|
||||||
|
"2375307394----12345678910\n" +
|
||||||
|
"2401645747----12345678910\n" +
|
||||||
|
"1515419818----1234567890\n" +
|
||||||
|
"3107367848----987654321\n";
|
||||||
|
|
||||||
|
private Bot getAvailableBot() throws ExecutionException, InterruptedException {
|
||||||
|
for (String it : qqList.split("\n")) {
|
||||||
|
var strings = it.split("----");
|
||||||
|
var bot = new Bot(new BotAccount(Long.parseLong(strings[0]), strings[1]), List.of());
|
||||||
|
|
||||||
|
if (bot.network.tryLogin$mirai_core().get() == LoginState.SUCCESS) {
|
||||||
|
MiraiLoggerKt.success(bot, "Login succeed");
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,28 @@
|
|||||||
package net.mamoe.mirai.contact
|
package net.mamoe.mirai.contact
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.message.Message
|
import net.mamoe.mirai.message.Message
|
||||||
|
import net.mamoe.mirai.message.defaults.MessageChain
|
||||||
import net.mamoe.mirai.message.defaults.PlainText
|
import net.mamoe.mirai.message.defaults.PlainText
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A contact is a [QQ] or a [Group] for one particular [Robot] instance only.
|
* A contact is a [QQ] or a [Group] for one particular [Bot] instance only.
|
||||||
*
|
*
|
||||||
* @param robot Owner [Robot]
|
* @param bot Owner [Bot]
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
abstract class Contact(val robot: Robot, val number: Long) {
|
abstract class Contact internal constructor(val bot: Bot, val number: Long) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async
|
* Async
|
||||||
*/
|
*/
|
||||||
abstract fun sendMessage(message: Message)
|
abstract fun sendMessage(message: MessageChain)
|
||||||
|
|
||||||
|
fun sendMessage(message: Message) {
|
||||||
|
if (message is MessageChain) {
|
||||||
|
return sendMessage(message)
|
||||||
|
}
|
||||||
|
return sendMessage(message.toChain())
|
||||||
|
}
|
||||||
|
|
||||||
fun sendMessage(message: String) {
|
fun sendMessage(message: String) {
|
||||||
this.sendMessage(PlainText(message))
|
this.sendMessage(PlainText(message))
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
package net.mamoe.mirai.contact
|
package net.mamoe.mirai.contact
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.message.Message
|
import net.mamoe.mirai.contact.Group.Companion.groupNumberToId
|
||||||
|
import net.mamoe.mirai.message.defaults.MessageChain
|
||||||
import net.mamoe.mirai.utils.ContactList
|
import net.mamoe.mirai.utils.ContactList
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
|
/**
|
||||||
|
* 群
|
||||||
|
*
|
||||||
|
* Java 获取 groupNumber: `group.getNumber()`
|
||||||
|
* Java 获取所属 bot: `group.getBot()`
|
||||||
|
* Java 获取群成员列表: `group.getMembers()`
|
||||||
|
* Java 获取 groupId: `group.getGroupId()`
|
||||||
|
*
|
||||||
|
* Java 调用 [groupNumberToId] : `Group.groupNumberToId(number)`
|
||||||
|
*/
|
||||||
|
class Group(bot: Bot, number: Long) : Contact(bot, number), Closeable {
|
||||||
val groupId = groupNumberToId(number)
|
val groupId = groupNumberToId(number)
|
||||||
val members = ContactList<QQ>()
|
val members = ContactList<QQ>()
|
||||||
|
|
||||||
override fun sendMessage(message: Message) {
|
override fun sendMessage(message: MessageChain) {
|
||||||
robot.network.messageHandler.sendGroupMessage(this, message)
|
bot.network.messageHandler.sendGroupMessage(this, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendXMLMessage(message: String) {
|
override fun sendXMLMessage(message: String) {
|
||||||
@ -23,7 +34,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun groupNumberToId(number: Long): Long {
|
fun groupNumberToId(number: Long): Long {//求你别出错
|
||||||
val left: Long = number.toString().let {
|
val left: Long = number.toString().let {
|
||||||
if (it.length < 6) {
|
if (it.length < 6) {
|
||||||
return@groupNumberToId number
|
return@groupNumberToId number
|
||||||
@ -61,7 +72,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun groupIdToNumber(id: Long): Long {
|
fun groupIdToNumber(id: Long): Long {//求你别出错
|
||||||
var left: Long = id.toString().let {
|
var left: Long = id.toString().let {
|
||||||
if (it.length < 6) {
|
if (it.length < 6) {
|
||||||
return@groupIdToNumber id
|
return@groupIdToNumber id
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
package net.mamoe.mirai.contact
|
package net.mamoe.mirai.contact
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.message.Message
|
import net.mamoe.mirai.message.Message
|
||||||
import net.mamoe.mirai.message.defaults.At
|
import net.mamoe.mirai.message.defaults.At
|
||||||
|
import net.mamoe.mirai.message.defaults.MessageChain
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QQ 账号.
|
* QQ 账号.
|
||||||
* 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Robot].
|
* 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot].
|
||||||
|
*
|
||||||
|
* Java 获取 qq 号: `qq.getNumber()`
|
||||||
|
* Java 获取所属 bot: `qq.getBot()`
|
||||||
*
|
*
|
||||||
* A QQ instance helps you to receive message from or send message to.
|
* 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.
|
* Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same.
|
||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
class QQ(robot: Robot, number: Long) : Contact(robot, number) {
|
class QQ(bot: Bot, number: Long) : Contact(bot, number) {
|
||||||
override fun sendMessage(message: Message) {
|
override fun sendMessage(message: MessageChain) {
|
||||||
robot.network.messageHandler.sendFriendMessage(this, message)
|
bot.network.messageHandler.sendFriendMessage(this, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendXMLMessage(message: String) {
|
override fun sendXMLMessage(message: String) {
|
||||||
|
@ -62,6 +62,6 @@ fun <C : KClass<E>, E : MiraiEvent> C.hookWhile(hook: (E) -> Boolean) {
|
|||||||
private class MiraiEventHookSimple<E : MiraiEvent>(clazz: Class<E>, val hook: (E) -> Boolean) : MiraiEventHook<E>(clazz) {
|
private class MiraiEventHookSimple<E : MiraiEvent>(clazz: Class<E>, val hook: (E) -> Boolean) : MiraiEventHook<E>(clazz) {
|
||||||
override fun accept(event: MiraiEvent?): Boolean {
|
override fun accept(event: MiraiEvent?): Boolean {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return hook.invoke(event as E)
|
return !hook.invoke(event as E)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package net.mamoe.mirai.event.events.bot;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
|
import net.mamoe.mirai.event.MiraiEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public abstract class BotEvent extends MiraiEvent {
|
||||||
|
private final Bot bot;
|
||||||
|
|
||||||
|
public BotEvent(@NotNull Bot bot) {
|
||||||
|
this.bot = Objects.requireNonNull(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Bot getBot() {
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package net.mamoe.mirai.event.events.bot
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.event.MiraiEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Him188moe
|
||||||
|
*/
|
||||||
|
class BotLoginEvent(val bot: Bot) : MiraiEvent()
|
||||||
|
|
||||||
|
class BotLogoutEvent(val bot: Bot) : MiraiEvent()
|
||||||
|
|
||||||
|
class BotMessageReceivedEvent(val bot: Bot, val type: Type, val message: String) : MiraiEvent() {
|
||||||
|
enum class Type {
|
||||||
|
FRIEND,
|
||||||
|
GROUP
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package net.mamoe.mirai.event.events.bot;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
|
|
||||||
|
public final class BotLoginSucceedEvent extends BotEvent {
|
||||||
|
|
||||||
|
public BotLoginSucceedEvent(Bot bot) {
|
||||||
|
super(bot);
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,18 @@
|
|||||||
package net.mamoe.mirai.event.events.group;
|
package net.mamoe.mirai.event.events.group;
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.contact.Group;
|
import net.mamoe.mirai.contact.Group;
|
||||||
import net.mamoe.mirai.event.events.robot.RobotEvent;
|
import net.mamoe.mirai.event.events.bot.BotEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public abstract class GroupEvent extends RobotEvent {
|
public abstract class GroupEvent extends BotEvent {
|
||||||
private final Group group;
|
private final Group group;
|
||||||
|
|
||||||
public GroupEvent(Robot robot, Group group) {
|
public GroupEvent(Bot bot, Group group) {
|
||||||
super(robot);
|
super(bot);
|
||||||
this.group = group;
|
this.group = group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.mamoe.mirai.event.events.group;
|
package net.mamoe.mirai.event.events.group;
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.contact.Group;
|
import net.mamoe.mirai.contact.Group;
|
||||||
import net.mamoe.mirai.contact.QQ;
|
import net.mamoe.mirai.contact.QQ;
|
||||||
import net.mamoe.mirai.message.defaults.MessageChain;
|
import net.mamoe.mirai.message.defaults.MessageChain;
|
||||||
@ -14,8 +14,8 @@ public final class GroupMessageEvent extends GroupEvent {
|
|||||||
private final MessageChain messageChain;
|
private final MessageChain messageChain;
|
||||||
private final String messageString;
|
private final String messageString;
|
||||||
|
|
||||||
public GroupMessageEvent(@NotNull Robot robot, @NotNull Group group, @NotNull QQ sender, @NotNull MessageChain messageChain) {
|
public GroupMessageEvent(@NotNull Bot bot, @NotNull Group group, @NotNull QQ sender, @NotNull MessageChain messageChain) {
|
||||||
super(robot, group);
|
super(bot, group);
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.messageChain = messageChain;
|
this.messageChain = messageChain;
|
||||||
this.messageString = messageChain.toString();
|
this.messageString = messageChain.toString();
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package net.mamoe.mirai.event.events.network;
|
package net.mamoe.mirai.event.events.network;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.event.Cancellable;
|
import net.mamoe.mirai.event.Cancellable;
|
||||||
import net.mamoe.mirai.network.packet.ClientPacket;
|
import net.mamoe.mirai.network.packet.ClientPacket;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Packet 已经 {@link ClientPacket#encode()}, 即将被发送
|
* Packet 已经 encoded, 即将被发送
|
||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public final class BeforePacketSendEvent extends ClientPacketEvent implements Cancellable {
|
public final class BeforePacketSendEvent extends ClientPacketEvent implements Cancellable {
|
||||||
public BeforePacketSendEvent(@NotNull ClientPacket packet) {
|
public BeforePacketSendEvent(@NotNull Bot bot, @NotNull ClientPacket packet) {
|
||||||
super(packet);
|
super(bot, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.event.events.network;
|
package net.mamoe.mirai.event.events.network;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.network.packet.ClientPacket;
|
import net.mamoe.mirai.network.packet.ClientPacket;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -7,8 +8,8 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public abstract class ClientPacketEvent extends PacketEvent {
|
public abstract class ClientPacketEvent extends PacketEvent {
|
||||||
public ClientPacketEvent(@NotNull ClientPacket packet) {
|
public ClientPacketEvent(@NotNull Bot bot, @NotNull ClientPacket packet) {
|
||||||
super(packet);
|
super(bot, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.mamoe.mirai.event.events.network;
|
package net.mamoe.mirai.event.events.network;
|
||||||
|
|
||||||
import net.mamoe.mirai.event.MiraiEvent;
|
import net.mamoe.mirai.Bot;
|
||||||
|
import net.mamoe.mirai.event.events.bot.BotEvent;
|
||||||
import net.mamoe.mirai.network.packet.Packet;
|
import net.mamoe.mirai.network.packet.Packet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -9,10 +10,11 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public abstract class PacketEvent extends MiraiEvent {
|
public abstract class PacketEvent extends BotEvent {
|
||||||
private final Packet packet;
|
private final Packet packet;
|
||||||
|
|
||||||
public PacketEvent(@NotNull Packet packet) {
|
public PacketEvent(@NotNull Bot bot, @NotNull Packet packet) {
|
||||||
|
super(bot);
|
||||||
this.packet = Objects.requireNonNull(packet);
|
this.packet = Objects.requireNonNull(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.event.events.network;
|
package net.mamoe.mirai.event.events.network;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.network.packet.ClientPacket;
|
import net.mamoe.mirai.network.packet.ClientPacket;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public final class PacketSentEvent extends ClientPacketEvent {
|
public final class PacketSentEvent extends ClientPacketEvent {
|
||||||
public PacketSentEvent(@NotNull ClientPacket packet) {
|
public PacketSentEvent(@NotNull Bot bot, @NotNull ClientPacket packet) {
|
||||||
super(packet);
|
super(bot, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package net.mamoe.mirai.event.events.network;
|
package net.mamoe.mirai.event.events.network;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.network.packet.ServerPacket;
|
import net.mamoe.mirai.network.packet.ServerPacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public abstract class ServerPacketEvent extends PacketEvent {
|
public abstract class ServerPacketEvent extends PacketEvent {
|
||||||
public ServerPacketEvent(ServerPacket packet) {
|
public ServerPacketEvent(Bot bot, ServerPacket packet) {
|
||||||
super(packet);
|
super(bot, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.event.events.network;
|
package net.mamoe.mirai.event.events.network;
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.event.Cancellable;
|
import net.mamoe.mirai.event.Cancellable;
|
||||||
import net.mamoe.mirai.network.packet.ServerPacket;
|
import net.mamoe.mirai.network.packet.ServerPacket;
|
||||||
import net.mamoe.mirai.network.packet.ServerVerificationCodePacket;
|
import net.mamoe.mirai.network.packet.ServerVerificationCodePacket;
|
||||||
@ -11,7 +12,7 @@ import net.mamoe.mirai.network.packet.ServerVerificationCodePacket;
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public final class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable {
|
public final class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable {
|
||||||
public ServerPacketReceivedEvent(ServerPacket packet) {
|
public ServerPacketReceivedEvent(Bot bot, ServerPacket packet) {
|
||||||
super(packet);
|
super(bot, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.mamoe.mirai.event.events.qq;
|
package net.mamoe.mirai.event.events.qq;
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.contact.QQ;
|
import net.mamoe.mirai.contact.QQ;
|
||||||
import net.mamoe.mirai.event.events.robot.RobotEvent;
|
import net.mamoe.mirai.event.events.bot.BotEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -10,11 +10,11 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public abstract class FriendEvent extends RobotEvent {
|
public abstract class FriendEvent extends BotEvent {
|
||||||
private final QQ qq;
|
private final QQ qq;
|
||||||
|
|
||||||
public FriendEvent(@NotNull Robot robot, @NotNull QQ qq) {
|
public FriendEvent(@NotNull Bot bot, @NotNull QQ qq) {
|
||||||
super(robot);
|
super(bot);
|
||||||
this.qq = Objects.requireNonNull(qq);
|
this.qq = Objects.requireNonNull(qq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.mamoe.mirai.event.events.qq;
|
package net.mamoe.mirai.event.events.qq;
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.contact.QQ;
|
import net.mamoe.mirai.contact.QQ;
|
||||||
import net.mamoe.mirai.message.defaults.MessageChain;
|
import net.mamoe.mirai.message.defaults.MessageChain;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -12,19 +12,14 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public final class FriendMessageEvent extends FriendEvent {
|
public final class FriendMessageEvent extends FriendEvent {
|
||||||
private final MessageChain messageChain;
|
private final MessageChain messageChain;
|
||||||
private final String messageString;
|
|
||||||
|
|
||||||
public FriendMessageEvent(@NotNull Robot robot, @NotNull QQ sender, @NotNull MessageChain messageChain) {
|
public FriendMessageEvent(@NotNull Bot bot, @NotNull QQ sender, @NotNull MessageChain messageChain) {
|
||||||
super(robot, sender);
|
super(bot, sender);
|
||||||
this.messageChain = Objects.requireNonNull(messageChain);
|
this.messageChain = Objects.requireNonNull(messageChain);
|
||||||
this.messageString = messageChain.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessageString() {
|
@NotNull
|
||||||
return messageString;
|
public MessageChain message() {
|
||||||
}
|
|
||||||
|
|
||||||
public MessageChain getMessageChain() {
|
|
||||||
return messageChain;
|
return messageChain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package net.mamoe.mirai.event.events.robot;
|
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
|
||||||
import net.mamoe.mirai.event.MiraiEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public abstract class RobotEvent extends MiraiEvent {
|
|
||||||
private final Robot robot;
|
|
||||||
|
|
||||||
public RobotEvent(@NotNull Robot robot) {
|
|
||||||
this.robot = Objects.requireNonNull(robot);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Robot getRobot() {
|
|
||||||
return robot;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package net.mamoe.mirai.event.events.robot
|
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot
|
|
||||||
import net.mamoe.mirai.event.MiraiEvent
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Him188moe
|
|
||||||
*/
|
|
||||||
class RobotLoginEvent(val robot: Robot) : MiraiEvent()
|
|
||||||
|
|
||||||
class RobotLogoutEvent(val robot: Robot) : MiraiEvent()
|
|
||||||
|
|
||||||
class RobotMessageReceivedEvent(val robot: Robot, val type: Type, val message: String) : MiraiEvent() {
|
|
||||||
enum class Type {
|
|
||||||
FRIEND,
|
|
||||||
GROUP
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package net.mamoe.mirai.event.events.robot;
|
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
|
||||||
|
|
||||||
public final class RobotLoginSucceedEvent extends RobotEvent {
|
|
||||||
|
|
||||||
public RobotLoginSucceedEvent(Robot robot) {
|
|
||||||
super(robot);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,8 +4,147 @@ package net.mamoe.mirai.message;
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
public enum FaceID {
|
public enum FaceID {
|
||||||
// TODO: 2019/9/1
|
Face_jingya(0),
|
||||||
|
Face_piezui(1),
|
||||||
|
Face_se(2),
|
||||||
|
Face_fadai(3),
|
||||||
|
Face_deyi(4),
|
||||||
|
Face_liulei(5),
|
||||||
|
Face_haixiu(6),
|
||||||
|
Face_bizui(7),
|
||||||
|
Face_shui(8),
|
||||||
|
Face_daku(9),
|
||||||
|
Face_ganga(10),
|
||||||
|
Face_fanu(11),
|
||||||
|
Face_tiaopi(12),
|
||||||
|
Face_ciya(13),
|
||||||
|
Face_weixiao(14),
|
||||||
|
Face_nanguo(15),
|
||||||
|
Face_ku(16),
|
||||||
|
Face_zhuakuang(18),
|
||||||
|
Face_tu(19),
|
||||||
|
Face_touxiao(20),
|
||||||
|
Face_keai(21),
|
||||||
|
Face_baiyan(22),
|
||||||
|
Face_aoman(23),
|
||||||
|
Face_ji_e(24),
|
||||||
|
Face_kun(25),
|
||||||
|
Face_jingkong(26),
|
||||||
|
Face_liuhan(27),
|
||||||
|
Face_hanxiao(28),
|
||||||
|
Face_dabing(29),
|
||||||
|
Face_fendou(30),
|
||||||
|
Face_zhouma(31),
|
||||||
|
Face_yiwen(32),
|
||||||
|
Face_yun(34),
|
||||||
|
Face_zhemo(35),
|
||||||
|
Face_shuai(36),
|
||||||
|
Face_kulou(37),
|
||||||
|
Face_qiaoda(38),
|
||||||
|
Face_zaijian(39),
|
||||||
|
Face_fadou(41),
|
||||||
|
Face_aiqing(42),
|
||||||
|
Face_tiaotiao(43),
|
||||||
|
Face_zhutou(46),
|
||||||
|
Face_yongbao(49),
|
||||||
|
Face_dan_gao(53),
|
||||||
|
Face_shandian(54),
|
||||||
|
Face_zhadan(55),
|
||||||
|
Face_dao(56),
|
||||||
|
Face_zuqiu(57),
|
||||||
|
Face_bianbian(59),
|
||||||
|
Face_kafei(60),
|
||||||
|
Face_fan(61),
|
||||||
|
Face_meigui(63),
|
||||||
|
Face_diaoxie(64),
|
||||||
|
Face_aixin(66),
|
||||||
|
Face_xinsui(67),
|
||||||
|
Face_liwu(69),
|
||||||
|
Face_taiyang(74),
|
||||||
|
Face_yueliang(75),
|
||||||
|
Face_qiang(76),
|
||||||
|
Face_ruo(77),
|
||||||
|
Face_woshou(78),
|
||||||
|
Face_shengli(79),
|
||||||
|
Face_feiwen(85),
|
||||||
|
Face_naohuo(86),
|
||||||
|
Face_xigua(89),
|
||||||
|
Face_lenghan(96),
|
||||||
|
Face_cahan(97),
|
||||||
|
Face_koubi(98),
|
||||||
|
Face_guzhang(99),
|
||||||
|
Face_qiudale(100),
|
||||||
|
Face_huaixiao(101),
|
||||||
|
Face_zuohengheng(102),
|
||||||
|
Face_youhengheng(103),
|
||||||
|
Face_haqian(104),
|
||||||
|
Face_bishi(105),
|
||||||
|
Face_weiqu(106),
|
||||||
|
Face_kuaikule(107),
|
||||||
|
Face_yinxian(108),
|
||||||
|
Face_qinqin(109),
|
||||||
|
Face_xia(110),
|
||||||
|
Face_kelian(111),
|
||||||
|
Face_caidao(112),
|
||||||
|
Face_pijiu(113),
|
||||||
|
Face_lanqiu(114),
|
||||||
|
Face_pingpang(115),
|
||||||
|
Face_shiai(116),
|
||||||
|
Face_piaochong(117),
|
||||||
|
Face_baoquan(118),
|
||||||
|
Face_gouyin(119),
|
||||||
|
Face_quantou(120),
|
||||||
|
Face_chajin(121),
|
||||||
|
Face_aini(122),
|
||||||
|
Face_bu(123),
|
||||||
|
Face_hao(124),
|
||||||
|
Face_zhuanquan(125),
|
||||||
|
Face_ketou(126),
|
||||||
|
Face_huitou(127),
|
||||||
|
Face_tiaosheng(128),
|
||||||
|
Face_huishou(129),
|
||||||
|
Face_jidong(130),
|
||||||
|
Face_jiewu(131),
|
||||||
|
Face_xianwen(132),
|
||||||
|
Face_zuotaiji(133),
|
||||||
|
Face_youtaiji(134),
|
||||||
|
Face_shuangxi(136),
|
||||||
|
Face_bianpao(137),
|
||||||
|
Face_denglong(138),
|
||||||
|
Face_facai(139),
|
||||||
|
Face_K_ge(140),
|
||||||
|
Face_gouwu(141),
|
||||||
|
Face_youjian(142),
|
||||||
|
Face_shuai_qi(143),
|
||||||
|
Face_hecai(144),
|
||||||
|
Face_qidao(145),
|
||||||
|
Face_baojin(146),
|
||||||
|
Face_bangbangtang(147),
|
||||||
|
Face_he_nai(148),
|
||||||
|
Face_xiamian(149),
|
||||||
|
Face_xiangjiao(150),
|
||||||
|
Face_feiji(151),
|
||||||
|
Face_kaiche(152),
|
||||||
|
Face_gaotiezuochetou(153),
|
||||||
|
Face_chexiang(154),
|
||||||
|
Face_gaotieyouchetou(155),
|
||||||
|
Face_duoyun(156),
|
||||||
|
Face_xiayu(157),
|
||||||
|
Face_chaopiao(158),
|
||||||
|
Face_xiongmao(159),
|
||||||
|
Face_dengpao(160),
|
||||||
|
Face_fengche(161),
|
||||||
|
Face_naozhong(162),
|
||||||
|
Face_dasan(163),
|
||||||
|
Face_caiqiu(164),
|
||||||
|
Face_zuanjie(165),
|
||||||
|
Face_shafa(166),
|
||||||
|
Face_zhijin(167),
|
||||||
|
Face_yao(168),
|
||||||
|
Face_shouqiang(169),
|
||||||
|
Face_qingwa(170),
|
||||||
|
|
||||||
|
// TODO: 2019/9/1 添加更多表情
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -18,4 +157,15 @@ public enum FaceID {
|
|||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FaceID ofId(int id) {
|
||||||
|
for (FaceID value : FaceID.values()) {
|
||||||
|
if (value.id == id) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,79 +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();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 把这个消息连接到另一个消息的头部. 相当于字符串相加
|
|
||||||
* <p>
|
|
||||||
* 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)}
|
|
||||||
* <p>
|
|
||||||
* E.g.:
|
|
||||||
* PlainText a = new PlainText("Hello ");
|
|
||||||
* PlainText b = new PlainText("world");
|
|
||||||
* PlainText c = a.concat(b);
|
|
||||||
* <p>
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
184
mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
Normal file
184
mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
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] 的使用非常类似.
|
||||||
|
*
|
||||||
|
* 比较 [Message] 与 [String] (使用 infix [Message.valueEquals]):
|
||||||
|
* `if(message valueEquals "你好") qq.sendMessage(message)`
|
||||||
|
*
|
||||||
|
* 连接 [Message] 与 [Message], [String], [BufferedImage] (使用 operator [Message.plus]):
|
||||||
|
* ```
|
||||||
|
* message = PlainText("Hello ")
|
||||||
|
* qq.sendMessage(message + "world")
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @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()
|
||||||
|
}
|
||||||
|
}
|
@ -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 概念
|
||||||
|
}
|
@ -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)
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +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() {
|
|
||||||
// TODO: 2019/9/1
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,43 +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 {
|
|
||||||
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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +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<Message> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return An unmodifiable list
|
|
||||||
*/
|
|
||||||
public List<Message> toList() {
|
|
||||||
return List.copyOf(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream<Message> stream() {
|
|
||||||
return new ArrayList<>(list).stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized String toString() {
|
|
||||||
return this.list.stream().map(Message::toString).collect(Collectors.joining(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized Message concat(@NotNull Message tail) {
|
|
||||||
this.list.add(tail);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,86 @@
|
|||||||
|
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 org.intellij.lang.annotations.MagicConstant
|
||||||
|
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<Message>()
|
||||||
|
|
||||||
|
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<Message> {
|
||||||
|
return list.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun size(): Int {
|
||||||
|
return list.size
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun containsType(@MagicConstant(valuesFromClass = MessageId::class) type: Int): Boolean {
|
||||||
|
for (message in list) {
|
||||||
|
if (message.type == type) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stream(): Stream<Message> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -10,10 +10,10 @@ import java.util.stream.Collectors
|
|||||||
object Protocol {
|
object Protocol {
|
||||||
val SERVER_IP: List<String> = object : ArrayList<String>() {
|
val SERVER_IP: List<String> = object : ArrayList<String>() {
|
||||||
init {
|
init {
|
||||||
add("183.60.56.29")
|
//add("183.60.56.29")
|
||||||
|
|
||||||
arrayOf(
|
arrayOf(
|
||||||
"sz3.tencent.com",
|
//"sz3.tencent.com",
|
||||||
"sz4.tencent.com",
|
"sz4.tencent.com",
|
||||||
"sz5.tencent.com",
|
"sz5.tencent.com",
|
||||||
"sz6.tencent.com",
|
"sz6.tencent.com",
|
||||||
@ -64,6 +64,11 @@ object Protocol {
|
|||||||
*/
|
*/
|
||||||
const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA"
|
const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送/接受消息中的一个const
|
||||||
|
*/
|
||||||
|
const val friendMessageConst1 = "00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91"
|
||||||
|
|
||||||
private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf()
|
private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf()
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
@file:JvmMultifileClass
|
@file:JvmMultifileClass
|
||||||
@file:JvmName("RobotNetworkHandler")
|
@file:JvmName("BotNetworkHandler")
|
||||||
|
|
||||||
package net.mamoe.mirai.network
|
package net.mamoe.mirai.network
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.MiraiServer
|
import net.mamoe.mirai.MiraiServer
|
||||||
import net.mamoe.mirai.Robot
|
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
import net.mamoe.mirai.contact.QQ
|
import net.mamoe.mirai.contact.QQ
|
||||||
|
import net.mamoe.mirai.event.events.bot.BotLoginSucceedEvent
|
||||||
import net.mamoe.mirai.event.events.network.BeforePacketSendEvent
|
import net.mamoe.mirai.event.events.network.BeforePacketSendEvent
|
||||||
import net.mamoe.mirai.event.events.network.PacketSentEvent
|
import net.mamoe.mirai.event.events.network.PacketSentEvent
|
||||||
import net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent
|
import net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent
|
||||||
import net.mamoe.mirai.event.events.qq.FriendMessageEvent
|
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.event.hookWhile
|
||||||
import net.mamoe.mirai.message.Message
|
import net.mamoe.mirai.message.Message
|
||||||
import net.mamoe.mirai.network.RobotNetworkHandler.*
|
import net.mamoe.mirai.message.defaults.MessageChain
|
||||||
|
import net.mamoe.mirai.network.BotNetworkHandler.*
|
||||||
import net.mamoe.mirai.network.packet.*
|
import net.mamoe.mirai.network.packet.*
|
||||||
import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
|
import net.mamoe.mirai.network.packet.action.*
|
||||||
import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
|
|
||||||
import net.mamoe.mirai.network.packet.login.*
|
import net.mamoe.mirai.network.packet.login.*
|
||||||
import net.mamoe.mirai.task.MiraiThreadPool
|
import net.mamoe.mirai.task.MiraiThreadPool
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
@ -29,15 +29,16 @@ import java.util.*
|
|||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.ScheduledFuture
|
import java.util.concurrent.ScheduledFuture
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.function.Supplier
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirai 的网络处理器, 它处理所有数据包([Packet])的发送和接收.
|
* Mirai 的网络处理器, 它处理所有数据包([Packet])的发送和接收.
|
||||||
* [RobotNetworkHandler] 是全程异步和线程安全的.
|
* [BotNetworkHandler] 是全程异步和线程安全的.
|
||||||
*
|
*
|
||||||
* [RobotNetworkHandler] 由 2 个模块构成:
|
* [BotNetworkHandler] 由 2 个模块构成:
|
||||||
* - [SocketHandler]: 处理数据包底层的发送([ByteArray])
|
* - [SocketHandler]: 处理数据包底层的发送([ByteArray])
|
||||||
* - [PacketHandler]: 制作 [Packet] 并传递给 [SocketHandler] 继续处理; 分析来自服务器的数据包并处理
|
* - [PacketHandler]: 制作 [Packet] 并传递给 [SocketHandler] 继续处理; 分析来自服务器的数据包并处理
|
||||||
*
|
*
|
||||||
@ -47,12 +48,12 @@ import kotlin.reflect.KClass
|
|||||||
* - [MessageHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket])
|
* - [MessageHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket])
|
||||||
* - [ActionHandler] 处理动作相关(踢人/加入群/好友列表等)
|
* - [ActionHandler] 处理动作相关(踢人/加入群/好友列表等)
|
||||||
*
|
*
|
||||||
* A RobotNetworkHandler is used to connect with Tencent servers.
|
* A BotNetworkHandler is used to connect with Tencent servers.
|
||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
@Suppress("EXPERIMENTAL_API_USAGE")//to simplify code
|
@Suppress("EXPERIMENTAL_API_USAGE")//to simplify code
|
||||||
class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
class BotNetworkHandler(private val bot: Bot) : Closeable {
|
||||||
private val socketHandler: SocketHandler = SocketHandler()
|
private val socketHandler: SocketHandler = SocketHandler()
|
||||||
|
|
||||||
val debugHandler = DebugHandler()
|
val debugHandler = DebugHandler()
|
||||||
@ -85,27 +86,26 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
|
|
||||||
//private | internal
|
//private | internal
|
||||||
|
|
||||||
internal fun tryLogin(): CompletableFuture<LoginState> = this.tryLogin(300)//登录回复非常快, 没必要等太久.
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook].
|
* 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook].
|
||||||
* 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCEED] 调用 [loginHandler]
|
* 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCESS] 调用 [loginHandler]
|
||||||
*
|
*
|
||||||
* @param touchingTimeoutMillis 连接每个服务器的 timeout
|
* @param touchingTimeoutMillis 连接每个服务器的 timeout
|
||||||
*/
|
*/
|
||||||
internal fun tryLogin(touchingTimeoutMillis: Long): CompletableFuture<LoginState> {
|
@JvmOverloads
|
||||||
|
internal fun tryLogin(touchingTimeoutMillis: Long = 200): CompletableFuture<LoginState> {
|
||||||
val ipQueue: LinkedList<String> = LinkedList(Protocol.SERVER_IP)
|
val ipQueue: LinkedList<String> = LinkedList(Protocol.SERVER_IP)
|
||||||
val future = CompletableFuture<LoginState>()
|
val future = CompletableFuture<LoginState>()
|
||||||
|
|
||||||
fun login() {
|
fun login() {
|
||||||
|
this.socketHandler.close()
|
||||||
val ip = ipQueue.poll()
|
val ip = ipQueue.poll()
|
||||||
if (ip == null) {
|
if (ip == null) {
|
||||||
future.complete(LoginState.UNKNOWN)//所有服务器均返回 UNKNOWN
|
future.complete(LoginState.UNKNOWN)//所有服务器均返回 UNKNOWN
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this@RobotNetworkHandler.socketHandler.touch(ip, touchingTimeoutMillis).get().let { state ->
|
this@BotNetworkHandler.socketHandler.touch(ip, touchingTimeoutMillis).get().let { state ->
|
||||||
if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) {
|
if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) {
|
||||||
login()
|
login()
|
||||||
} else {
|
} else {
|
||||||
@ -122,8 +122,17 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
*/
|
*/
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
internal fun distributePacket(packet: ServerPacket) {
|
internal fun distributePacket(packet: ServerPacket) {
|
||||||
packet.decode()
|
try {
|
||||||
if (ServerPacketReceivedEvent(packet).broadcast().isCancelled) {
|
packet.decode()
|
||||||
|
} catch (e: java.lang.Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
bot.debug("Packet=$packet")
|
||||||
|
bot.debug("Packet size=" + packet.input.goto(0).readAllBytes().size)
|
||||||
|
bot.debug("Packet data=" + packet.input.goto(0).readAllBytes().toUHexString())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ServerPacketReceivedEvent(bot, packet).broadcast().isCancelled) {
|
||||||
debugHandler.onPacketReceived(packet)
|
debugHandler.onPacketReceived(packet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -145,6 +154,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
|
|
||||||
internal var loginFuture: CompletableFuture<LoginState>? = null
|
internal var loginFuture: CompletableFuture<LoginState>? = null
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
private fun restartSocket() {
|
private fun restartSocket() {
|
||||||
socket?.close()
|
socket?.close()
|
||||||
socket = DatagramSocket(0)
|
socket = DatagramSocket(0)
|
||||||
@ -176,14 +186,14 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
* Start network and touch the server
|
* Start network and touch the server
|
||||||
*/
|
*/
|
||||||
internal fun touch(serverAddress: String, timeoutMillis: Long): CompletableFuture<LoginState> {
|
internal fun touch(serverAddress: String, timeoutMillis: Long): CompletableFuture<LoginState> {
|
||||||
MiraiLogger.info("Connecting server: $serverAddress")
|
bot.info("Connecting server: $serverAddress")
|
||||||
this.loginFuture = CompletableFuture()
|
this.loginFuture = CompletableFuture()
|
||||||
|
|
||||||
socketHandler.serverIP = serverAddress
|
socketHandler.serverIP = serverAddress
|
||||||
sendPacket(ClientTouchPacket(robot.account.qqNumber, socketHandler.serverIP))
|
waitForPacket(ServerPacket::class, timeoutMillis) {
|
||||||
waitForPacket(ServerTouchResponsePacket::class, timeoutMillis) {
|
|
||||||
loginFuture!!.complete(LoginState.TIMEOUT)
|
loginFuture!!.complete(LoginState.TIMEOUT)
|
||||||
}
|
}
|
||||||
|
sendPacket(ClientTouchPacket(bot.account.qqNumber, socketHandler.serverIP))
|
||||||
|
|
||||||
return this.loginFuture!!
|
return this.loginFuture!!
|
||||||
}
|
}
|
||||||
@ -191,6 +201,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
/**
|
/**
|
||||||
* Not async
|
* Not async
|
||||||
*/
|
*/
|
||||||
|
@Synchronized
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
internal fun sendPacket(packet: ClientPacket) {
|
internal fun sendPacket(packet: ClientPacket) {
|
||||||
checkNotNull(socket) { "network closed" }
|
checkNotNull(socket) { "network closed" }
|
||||||
@ -201,25 +212,25 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
try {
|
try {
|
||||||
packet.encodePacket()
|
packet.encodePacket()
|
||||||
|
|
||||||
if (BeforePacketSendEvent(packet).broadcast().isCancelled) {
|
if (BeforePacketSendEvent(bot, packet).broadcast().isCancelled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val data = packet.toByteArray()
|
val data = packet.toByteArray()
|
||||||
socket!!.send(DatagramPacket(data, data.size))
|
socket!!.send(DatagramPacket(data, data.size))
|
||||||
MiraiLogger info "Packet sent: $packet"
|
bot cyanL "Packet sent: $packet"
|
||||||
|
|
||||||
PacketSentEvent(packet).broadcast()
|
PacketSentEvent(bot, packet).broadcast()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun <P : ServerPacket> waitForPacket(packetClass: KClass<P>, timeoutMillis: Long, timeout: () -> Unit) {
|
internal fun <P : ServerPacket> waitForPacket(packetClass: KClass<P>, timeoutMillis: Long, timeout: () -> Unit) {
|
||||||
var got = false
|
var got = false
|
||||||
ServerPacketReceivedEvent::class.hookWhile {
|
ServerPacketReceivedEvent::class.hookWhile {
|
||||||
if (packetClass.isInstance(it.packet)) {
|
if (packetClass.isInstance(it.packet) && it.bot == bot) {
|
||||||
got = true
|
got = true
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@ -227,6 +238,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MiraiThreadPool.getInstance().submit {
|
MiraiThreadPool.getInstance().submit {
|
||||||
val startingTime = System.currentTimeMillis()
|
val startingTime = System.currentTimeMillis()
|
||||||
while (!got) {
|
while (!got) {
|
||||||
@ -248,6 +260,10 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
this.loginFuture = null
|
this.loginFuture = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isClosed(): Boolean {
|
||||||
|
return this.socket?.isClosed ?: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,9 +282,11 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
*/
|
*/
|
||||||
inner class DebugHandler : PacketHandler() {
|
inner class DebugHandler : PacketHandler() {
|
||||||
override fun onPacketReceived(packet: ServerPacket) {
|
override fun onPacketReceived(packet: ServerPacket) {
|
||||||
MiraiLogger info "Packet received: $packet"
|
if (!packet.javaClass.name.endsWith("Encrypted") && !packet.javaClass.name.endsWith("Raw")) {
|
||||||
|
bot notice "Packet received: $packet"
|
||||||
|
}
|
||||||
if (packet is ServerEventPacket) {
|
if (packet is ServerEventPacket) {
|
||||||
sendPacket(ClientMessageResponsePacket(robot.account.qqNumber, packet.packetId, sessionKey, packet.eventIdentity))
|
sendPacket(ClientMessageResponsePacket(bot.account.qqNumber, packet.packetId, sessionKey, packet.eventIdentity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +299,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
private lateinit var token0825: ByteArray
|
private lateinit var token0825: ByteArray
|
||||||
private var loginTime: Int = 0
|
private var loginTime: Int = 0
|
||||||
private lateinit var loginIP: String
|
private lateinit var loginIP: String
|
||||||
private var tgtgtKey: ByteArray? = null
|
private var tgtgtKey: ByteArray = getRandomByteArray(16)
|
||||||
|
|
||||||
private var tlv0105: ByteArray = lazyEncode {
|
private var tlv0105: ByteArray = lazyEncode {
|
||||||
it.writeHex("01 05 00 30")
|
it.writeHex("01 05 00 30")
|
||||||
@ -296,8 +314,8 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
*/
|
*/
|
||||||
private lateinit var sessionResponseDecryptionKey: ByteArray
|
private lateinit var sessionResponseDecryptionKey: ByteArray
|
||||||
|
|
||||||
private var verificationCodeCacheId: Int = 0
|
private var captchaSectionId: Int = 1
|
||||||
private var verificationCodeCache: ByteArray? = byteArrayOf()//每次包只发一部分验证码来
|
private var captchaCache: ByteArray? = byteArrayOf()//每次包只发一部分验证码来
|
||||||
|
|
||||||
|
|
||||||
private var heartbeatFuture: ScheduledFuture<*>? = null
|
private var heartbeatFuture: ScheduledFuture<*>? = null
|
||||||
@ -309,13 +327,12 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
if (packet.serverIP != null) {//redirection
|
if (packet.serverIP != null) {//redirection
|
||||||
socketHandler.serverIP = packet.serverIP!!
|
socketHandler.serverIP = packet.serverIP!!
|
||||||
//connect(packet.serverIP!!)
|
//connect(packet.serverIP!!)
|
||||||
sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, robot.account.qqNumber))
|
sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, bot.account.qqNumber))
|
||||||
} else {//password submission
|
} else {//password submission
|
||||||
this.loginIP = packet.loginIP
|
this.loginIP = packet.loginIP
|
||||||
this.loginTime = packet.loginTime
|
this.loginTime = packet.loginTime
|
||||||
this.token0825 = packet.token0825
|
this.token0825 = packet.token0825
|
||||||
this.tgtgtKey = packet.tgtgtKey
|
sendPacket(ClientPasswordSubmissionPacket(bot.account.qqNumber, bot.account.password, packet.loginTime, packet.loginIP, this.tgtgtKey, packet.token0825))
|
||||||
sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,136 +341,117 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerLoginResponseVerificationCodeInitPacket -> {
|
|
||||||
//[token00BA]来源之一: 验证码
|
|
||||||
this.token00BA = packet.token00BA
|
|
||||||
this.verificationCodeCache = packet.verifyCodePart1
|
|
||||||
|
|
||||||
if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
|
|
||||||
this.verificationCodeCacheId = 1
|
|
||||||
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, robot.account.qqNumber, this.token0825, this.verificationCodeCacheId, this.token00BA))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is ServerVerificationCodeCorrectPacket -> {
|
is ServerVerificationCodeCorrectPacket -> {
|
||||||
this.tgtgtKey = getRandomByteArray(16)
|
this.tgtgtKey = getRandomByteArray(16)
|
||||||
this.token00BA = packet.token00BA
|
this.token00BA = packet.token00BA
|
||||||
sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
|
sendPacket(ClientLoginResendPacket3105(bot.account.qqNumber, bot.account.password, this.loginTime, this.loginIP, this.tgtgtKey, this.token0825, this.token00BA))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is ServerLoginResponseVerificationCodeInitPacket -> {
|
||||||
|
//[token00BA]来源之一: 验证码
|
||||||
|
this.token00BA = packet.token00BA
|
||||||
|
this.captchaCache = packet.verifyCodePart1
|
||||||
|
|
||||||
|
if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
|
||||||
|
this.captchaSectionId = 1
|
||||||
|
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, bot.account.qqNumber, this.token0825, this.captchaSectionId++, this.token00BA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
is ServerVerificationCodeTransmissionPacket -> {
|
is ServerVerificationCodeTransmissionPacket -> {
|
||||||
if (packet is ServerVerificationCodeWrongPacket) {
|
if (packet is ServerVerificationCodeWrongPacket) {
|
||||||
this.verificationCodeCacheId = 0
|
bot error "验证码错误, 请重新输入"
|
||||||
this.verificationCodeCache = byteArrayOf()
|
captchaSectionId = 1
|
||||||
|
this.captchaCache = byteArrayOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.verificationCodeCacheId++
|
this.captchaCache = this.captchaCache!! + packet.captchaSectionN
|
||||||
this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN
|
|
||||||
|
|
||||||
this.token00BA = packet.token00BA
|
this.token00BA = packet.token00BA
|
||||||
|
|
||||||
if (packet.transmissionCompleted) {
|
if (packet.transmissionCompleted) {
|
||||||
(MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.verificationCodeCache!!)
|
bot notice (CharImageUtil.createCharImg(ImageIO.read(this.captchaCache!!.inputStream())))
|
||||||
println(CharImageUtil.createCharImg(ImageIO.read(this.verificationCodeCache!!.inputStream())))
|
bot notice ("需要验证码登录, 验证码为 4 字母")
|
||||||
println("需要验证码登录")
|
try {
|
||||||
println("若看不清请查根目录下 VerificationCode.png")
|
(MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.captchaCache!!)
|
||||||
println("若要更换验证码, 请直接回车")
|
bot notice ("若看不清字符图片, 请查看 Mirai 根目录下 VerificationCode.png")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
bot notice "无法写出验证码文件, 请尝试查看以上字符图片"
|
||||||
|
}
|
||||||
|
bot notice ("若要更换验证码, 请直接回车")
|
||||||
val code = Scanner(System.`in`).nextLine()
|
val code = Scanner(System.`in`).nextLine()
|
||||||
if (code.isEmpty()) {
|
if (code.isEmpty() || code.length != 4) {
|
||||||
sendPacket(ClientVerificationCodeRefreshPacket(robot.account.qqNumber, token0825, packet.verificationSessionId + 1))
|
this.captchaCache = byteArrayOf()
|
||||||
|
this.captchaSectionId = 1
|
||||||
|
sendPacket(ClientVerificationCodeRefreshPacket(packet.packetIdLast + 1, bot.account.qqNumber, token0825))
|
||||||
} else {
|
} else {
|
||||||
sendPacket(ClientVerificationCodeSubmitPacket(robot.account.qqNumber, token0825, packet.verificationSessionId + 1, code, packet.verificationToken))
|
sendPacket(ClientVerificationCodeSubmitPacket(packet.packetIdLast + 1, bot.account.qqNumber, token0825, code, packet.verificationToken))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.verificationSessionId + 1, robot.account.qqNumber, this.token0825, this.verificationCodeCacheId, this.token00BA))
|
sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.packetIdLast + 1, bot.account.qqNumber, token0825, captchaSectionId++, token00BA))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerLoginResponseSuccessPacket -> {
|
is ServerLoginResponseSuccessPacket -> {
|
||||||
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
|
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
|
||||||
sendPacket(ClientSessionRequestPacket(robot.account.qqNumber, socketHandler.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
|
sendPacket(ClientSessionRequestPacket(bot.account.qqNumber, socketHandler.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
|
||||||
}
|
}
|
||||||
|
|
||||||
//是ClientPasswordSubmissionPacket之后服务器回复的
|
//是ClientPasswordSubmissionPacket之后服务器回复的
|
||||||
is ServerLoginResponseResendPacket -> {
|
is ServerLoginResponseKeyExchangePacket -> {
|
||||||
//if (packet.tokenUnknown != null) {
|
//if (packet.tokenUnknown != null) {
|
||||||
//this.token00BA = packet.token00BA!!
|
//this.token00BA = packet.token00BA!!
|
||||||
//println("token00BA changed!!! to " + token00BA.toUByteArray())
|
//println("token00BA changed!!! to " + token00BA.toUByteArray())
|
||||||
//}
|
//}
|
||||||
if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) {
|
if (packet.flag == ServerLoginResponseKeyExchangePacket.Flag.`08 36 31 03`) {
|
||||||
this.tgtgtKey = packet.tgtgtKey
|
this.tgtgtKey = packet.tgtgtKey
|
||||||
sendPacket(ClientLoginResendPacket3104(
|
sendPacket(ClientLoginResendPacket3104(bot.account.qqNumber, bot.account.password, loginTime, loginIP, tgtgtKey, token0825, packet.tokenUnknown
|
||||||
robot.account.qqNumber,
|
?: this.token00BA, packet.tlv0006))
|
||||||
robot.account.password,
|
|
||||||
this.loginTime,
|
|
||||||
this.loginIP,
|
|
||||||
this.tgtgtKey!!,
|
|
||||||
this.token0825,
|
|
||||||
when (packet.tokenUnknown != null) {
|
|
||||||
true -> packet.tokenUnknown!!
|
|
||||||
false -> this.token00BA
|
|
||||||
},
|
|
||||||
packet._0836_tlv0006_encr
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
sendPacket(ClientLoginResendPacket3106(
|
sendPacket(ClientLoginResendPacket3106(bot.account.qqNumber, bot.account.password, loginTime, loginIP, tgtgtKey, token0825, packet.tokenUnknown
|
||||||
robot.account.qqNumber,
|
?: token00BA, packet.tlv0006))
|
||||||
robot.account.password,
|
|
||||||
this.loginTime,
|
|
||||||
this.loginIP,
|
|
||||||
this.tgtgtKey!!,
|
|
||||||
this.token0825,
|
|
||||||
when (packet.tokenUnknown != null) {
|
|
||||||
true -> packet.tokenUnknown!!
|
|
||||||
false -> this.token00BA
|
|
||||||
},
|
|
||||||
packet._0836_tlv0006_encr
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerSessionKeyResponsePacket -> {
|
is ServerSessionKeyResponsePacket -> {
|
||||||
sessionKey = packet.sessionKey
|
sessionKey = packet.sessionKey
|
||||||
heartbeatFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
|
heartbeatFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
|
||||||
sendPacket(ClientHeartbeatPacket(robot.account.qqNumber, sessionKey))
|
sendPacket(ClientHeartbeatPacket(bot.account.qqNumber, sessionKey))
|
||||||
}, 90000, 90000, TimeUnit.MILLISECONDS)
|
}, 90000, 90000, TimeUnit.MILLISECONDS)
|
||||||
|
|
||||||
RobotLoginSucceedEvent(robot).broadcast()
|
BotLoginSucceedEvent(bot).broadcast()
|
||||||
|
|
||||||
//登录成功后会收到大量上次的消息, 忽略掉
|
//登录成功后会收到大量上次的消息, 忽略掉
|
||||||
MiraiThreadPool.getInstance().schedule({
|
MiraiThreadPool.getInstance().schedule({
|
||||||
(packetHandlers[MessageHandler::class] as MessageHandler).ignoreMessage = false
|
messageHandler.ignoreMessage = false
|
||||||
}, 2, TimeUnit.SECONDS)
|
}, 2, TimeUnit.SECONDS)
|
||||||
|
|
||||||
this.tlv0105 = packet.tlv0105
|
this.tlv0105 = packet.tlv0105
|
||||||
sendPacket(ClientChangeOnlineStatusPacket(robot.account.qqNumber, sessionKey, ClientLoginStatus.ONLINE))
|
sendPacket(ClientChangeOnlineStatusPacket(bot.account.qqNumber, sessionKey, ClientLoginStatus.ONLINE))
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerLoginSuccessPacket -> {
|
is ServerLoginSuccessPacket -> {
|
||||||
socketHandler.loginFuture!!.complete(LoginState.SUCCEED)
|
socketHandler.loginFuture!!.complete(LoginState.SUCCESS)
|
||||||
sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey))
|
sendPacket(ClientSKeyRequestPacket(bot.account.qqNumber, sessionKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerSKeyResponsePacket -> {
|
is ServerSKeyResponsePacket -> {
|
||||||
val actionHandler = packetHandlers[ActionHandler::class] as ActionHandler
|
|
||||||
actionHandler.sKey = packet.sKey
|
actionHandler.sKey = packet.sKey
|
||||||
actionHandler.cookies = "uin=o" + robot.account.qqNumber + ";skey=" + actionHandler.sKey + ";"
|
actionHandler.cookies = "uin=o" + bot.account.qqNumber + ";skey=" + actionHandler.sKey + ";"
|
||||||
|
|
||||||
sKeyRefresherFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
|
sKeyRefresherFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
|
||||||
sendPacket(ClientSKeyRefreshmentRequestPacket(robot.account.qqNumber, sessionKey))
|
sendPacket(ClientSKeyRefreshmentRequestPacket(bot.account.qqNumber, sessionKey))
|
||||||
}, 1800000, 1800000, TimeUnit.MILLISECONDS)
|
}, 1800000, 1800000, TimeUnit.MILLISECONDS)
|
||||||
|
|
||||||
actionHandler.gtk = getGTK(actionHandler.sKey)
|
actionHandler.gtk = getGTK(actionHandler.sKey)
|
||||||
sendPacket(ClientAccountInfoRequestPacket(robot.account.qqNumber, sessionKey))
|
sendPacket(ClientAccountInfoRequestPacket(bot.account.qqNumber, sessionKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerEventPacket.Raw -> distributePacket(packet.distribute())
|
is ServerEventPacket.Raw -> distributePacket(packet.distribute())
|
||||||
|
|
||||||
is ServerVerificationCodePacket.Encrypted -> distributePacket(packet.decrypt())
|
is ServerVerificationCodePacket.Encrypted -> distributePacket(packet.decrypt())
|
||||||
is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> distributePacket(packet.decrypt())
|
is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> distributePacket(packet.decrypt())
|
||||||
is ServerLoginResponseResendPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey!!))
|
is ServerLoginResponseKeyExchangePacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey))
|
||||||
is ServerLoginResponseSuccessPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey!!))
|
is ServerLoginResponseSuccessPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey))
|
||||||
is ServerSessionKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(this.sessionResponseDecryptionKey))
|
is ServerSessionKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(this.sessionResponseDecryptionKey))
|
||||||
is ServerTouchResponsePacket.Encrypted -> distributePacket(packet.decrypt())
|
is ServerTouchResponsePacket.Encrypted -> distributePacket(packet.decrypt())
|
||||||
is ServerSKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
|
is ServerSKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
|
||||||
@ -473,8 +471,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
this.verificationCodeCache = null
|
this.captchaCache = null
|
||||||
this.tgtgtKey = null
|
|
||||||
|
|
||||||
this.heartbeatFuture?.cancel(true)
|
this.heartbeatFuture?.cancel(true)
|
||||||
this.sKeyRefresherFuture?.cancel(true)
|
this.sKeyRefresherFuture?.cancel(true)
|
||||||
@ -490,6 +487,22 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
inner class MessageHandler : PacketHandler() {
|
inner class MessageHandler : PacketHandler() {
|
||||||
internal var ignoreMessage: Boolean = false
|
internal var ignoreMessage: Boolean = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
//todo for test
|
||||||
|
FriendMessageEvent::class.hookWhile {
|
||||||
|
if (socketHandler.isClosed()) {
|
||||||
|
return@hookWhile false
|
||||||
|
}
|
||||||
|
if (it.message() valueEquals "你好") {
|
||||||
|
it.qq.sendMessage("你好!")
|
||||||
|
} else if (it.message().toString().startsWith("复读")) {
|
||||||
|
it.qq.sendMessage(it.message())
|
||||||
|
}
|
||||||
|
|
||||||
|
return@hookWhile true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPacketReceived(packet: ServerPacket) {
|
override fun onPacketReceived(packet: ServerPacket) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ServerGroupUploadFileEventPacket -> {
|
is ServerGroupUploadFileEventPacket -> {
|
||||||
@ -501,15 +514,18 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message)
|
FriendMessageEvent(bot, bot.contacts.getQQ(packet.qq), packet.message).broadcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerGroupMessageEventPacket -> {
|
is ServerGroupMessageEventPacket -> {
|
||||||
//todo message chain
|
//todo message chain
|
||||||
//GroupMessageEvent(this.robot, robot.contacts.getGroupByNumber(packet.groupNumber), robot.contacts.getQQ(packet.qq), packet.message)
|
//GroupMessageEvent(this.bot, bot.contacts.getGroupByNumber(packet.groupNumber), bot.contacts.getQQ(packet.qq), packet.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnknownServerEventPacket -> {
|
||||||
|
//todo
|
||||||
}
|
}
|
||||||
|
|
||||||
is UnknownServerEventPacket,
|
|
||||||
is ServerSendFriendMessageResponsePacket,
|
is ServerSendFriendMessageResponsePacket,
|
||||||
is ServerSendGroupMessageResponsePacket -> {
|
is ServerSendGroupMessageResponsePacket -> {
|
||||||
//ignored
|
//ignored
|
||||||
@ -520,14 +536,13 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendFriendMessage(qq: QQ, message: Message) {
|
fun sendFriendMessage(qq: QQ, message: MessageChain) {
|
||||||
TODO()
|
sendPacket(ClientSendFriendMessagePacket(bot.account.qqNumber, qq.number, sessionKey, message))
|
||||||
//sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendGroupMessage(group: Group, message: Message): Unit {
|
fun sendGroupMessage(group: Group, message: Message): Unit {
|
||||||
TODO()
|
TODO()
|
||||||
//sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message))
|
//sendPacket(ClientSendGroupMessagePacket(group.groupId, bot.account.qqNumber, sessionKey, message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,15 +552,94 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
|
|||||||
*/
|
*/
|
||||||
inner class ActionHandler : PacketHandler() {
|
inner class ActionHandler : PacketHandler() {
|
||||||
internal lateinit var cookies: String
|
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
|
internal var gtk: Int = 0
|
||||||
|
|
||||||
override fun onPacketReceived(packet: ServerPacket) {
|
private val addFriendSessions = Collections.synchronizedCollection(mutableListOf<AddFriendSession>())
|
||||||
|
|
||||||
|
override fun onPacketReceived(packet: ServerPacket) {
|
||||||
|
when (packet) {
|
||||||
|
is ServerCanAddFriendResponsePacket -> {
|
||||||
|
this.addFriendSessions.forEach {
|
||||||
|
it.onPacketReceived(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addFriend(qqNumber: Long, message: Supplier<String>) {
|
||||||
|
addFriend(qqNumber, lazy { message.get() })
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
|
fun addFriend(qqNumber: Long, message: Lazy<String> = lazyOf("")): CompletableFuture<AddFriendResult> {
|
||||||
|
val future = CompletableFuture<AddFriendResult>()
|
||||||
|
val session = AddFriendSession(qqNumber, future, message)
|
||||||
|
addFriendSessions.add(session)
|
||||||
|
session.sendAddRequest();
|
||||||
|
return future
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class AddFriendSession(
|
||||||
|
private val qq: Long,
|
||||||
|
private val future: CompletableFuture<AddFriendResult>,
|
||||||
|
private val message: Lazy<String>
|
||||||
|
) : Closeable {
|
||||||
|
lateinit var id: ByteArray
|
||||||
|
|
||||||
|
fun onPacketReceived(packet: ServerPacket) {
|
||||||
|
if (!::id.isInitialized) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
when (packet) {
|
||||||
|
is ServerCanAddFriendResponsePacket -> {
|
||||||
|
if (!(packet.idByteArray[2] == id[0] && packet.idByteArray[3] == id[1])) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
when (packet.state) {
|
||||||
|
ServerCanAddFriendResponsePacket.State.FAILED -> {
|
||||||
|
future.complete(AddFriendResult.FAILED)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerCanAddFriendResponsePacket.State.ALREADY_ADDED -> {
|
||||||
|
future.complete(AddFriendResult.ALREADY_ADDED)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> {
|
||||||
|
sendPacket(ClientAddFriendPacket(bot.account.qqNumber, qq, sessionKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendAddRequest() {
|
||||||
|
sendPacket(ClientCanAddFriendPacket(bot.account.qqNumber, qq, sessionKey).also { this.id = it.packetIdLast })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
addFriendSessions.remove(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package net.mamoe.mirai.network.packet
|
|||||||
|
|
||||||
import lombok.Getter
|
import lombok.Getter
|
||||||
import net.mamoe.mirai.network.Protocol
|
import net.mamoe.mirai.network.Protocol
|
||||||
|
import net.mamoe.mirai.network.packet.PacketNameFormatter.adjustName
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -20,7 +21,7 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
val annotation = this.javaClass.getAnnotation(PacketId::class.java)
|
val annotation = this.javaClass.getAnnotation(PacketId::class.java)
|
||||||
idHex = annotation.value
|
idHex = annotation.value.trim()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.writeHex(Protocol.head)
|
this.writeHex(Protocol.head)
|
||||||
@ -29,7 +30,6 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet {
|
|||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
throw RuntimeException(e)
|
throw RuntimeException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@ -60,10 +60,20 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet {
|
|||||||
return toByteArray()
|
return toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun getFixedId(): String = when (this.idHex.length) {
|
||||||
|
0 -> "__ __ __ __"
|
||||||
|
2 -> this.idHex + " __ __ __"
|
||||||
|
5 -> this.idHex + " __ __"
|
||||||
|
7 -> this.idHex + " __"
|
||||||
|
else -> this.idHex
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return this.javaClass.simpleName + this.getAllDeclaredFields().joinToString(", ", "{", "}") {
|
return adjustName(this.javaClass.simpleName + "(${this.getFixedId()})") + this.getAllDeclaredFields().filterNot { it.name == "idHex" || it.name == "idByteArray" || it.name == "encoded" }.joinToString(", ", "{", "}") {
|
||||||
it.trySetAccessible(); it.name + "=" + it.get(this).let { value ->
|
it.trySetAccessible(); it.name + "=" + it.get(this).let { value ->
|
||||||
when (value) {
|
when (value) {
|
||||||
|
null -> null
|
||||||
is ByteArray -> value.toUHexString()
|
is ByteArray -> value.toUHexString()
|
||||||
is UByteArray -> value.toUHexString()
|
is UByteArray -> value.toUHexString()
|
||||||
else -> value.toString()
|
else -> value.toString()
|
||||||
@ -144,12 +154,6 @@ fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, lo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
@ExperimentalUnsignedTypes
|
|
||||||
fun main() {
|
|
||||||
println(lazyEncode { it.writeTLV0006(1994701021, "D1 A5 C8 BB E1 Q3 CC DD", 131513, "123.123.123.123", "AA BB CC DD EE FF AA BB CC".hexToBytes()) }.toUByteArray().toUHexString())
|
|
||||||
}*/
|
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
@TestedSuccessfully
|
@TestedSuccessfully
|
||||||
fun DataOutputStream.writeCRC32() = writeCRC32(getRandomByteArray(16))
|
fun DataOutputStream.writeCRC32() = writeCRC32(getRandomByteArray(16))
|
||||||
@ -166,11 +170,10 @@ fun DataOutputStream.writeCRC32(key: ByteArray) {
|
|||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
@TestedSuccessfully
|
@TestedSuccessfully
|
||||||
fun DataOutputStream.writeDeviceName(random: Boolean = false) {
|
fun DataOutputStream.writeDeviceName(random: Boolean = false) {
|
||||||
val deviceName: String
|
val deviceName: String = if (random) {
|
||||||
if (random) {
|
String(getRandomByteArray(10))
|
||||||
deviceName = String(getRandomByteArray(10))
|
|
||||||
} else {
|
} else {
|
||||||
deviceName = InetAddress.getLocalHost().hostName
|
InetAddress.getLocalHost().hostName
|
||||||
}
|
}
|
||||||
this.writeShort(deviceName.length + 2)
|
this.writeShort(deviceName.length + 2)
|
||||||
this.writeShort(deviceName.length)
|
this.writeShort(deviceName.length)
|
||||||
@ -209,7 +212,7 @@ fun Int.toLByteArray(): ByteArray = byteArrayOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator)
|
fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator)
|
||||||
|
|
||||||
internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray())
|
internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray())
|
||||||
|
|
||||||
@ -226,7 +229,7 @@ fun DataOutputStream.writeZero(count: Int) {
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun DataOutputStream.writeRandom(length: Int) {
|
fun DataOutputStream.writeRandom(length: Int) {
|
||||||
repeat(length) {
|
repeat(length) {
|
||||||
this.writeByte((Math.random() * 255).toInt().toByte().toInt())
|
this.writeByte((Math.random() * 255).toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,4 +243,13 @@ fun DataOutputStream.writeQQ(qq: Long) {
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) {
|
fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) {
|
||||||
this.write(groupIdOrGroupNumber.toUInt().toByteArray())
|
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())
|
||||||
}
|
}
|
@ -42,7 +42,7 @@ class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(inp
|
|||||||
fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
|
fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
|
||||||
this.input goto 14
|
this.input goto 14
|
||||||
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
|
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
|
||||||
return ServerAccountInfoResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
|
return ServerAccountInfoResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream()).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +0,0 @@
|
|||||||
package net.mamoe.mirai.network.packet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Him188moe
|
|
||||||
*/
|
|
||||||
public interface Packet {
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,28 @@
|
|||||||
|
package net.mamoe.mirai.network.packet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Him188moe
|
||||||
|
*/
|
||||||
|
interface Packet {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object PacketNameFormatter {
|
||||||
|
@JvmSynthetic
|
||||||
|
private var longestNameLength: Int = 43
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
|
fun adjustName(name: String): String {
|
||||||
|
if (name.length > longestNameLength) {
|
||||||
|
longestNameLength = name.length
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringBuilder().apply {
|
||||||
|
repeat(longestNameLength - name.length) {
|
||||||
|
this.append(" ")
|
||||||
|
}
|
||||||
|
}.toString() + name
|
||||||
|
}
|
||||||
|
}
|
@ -58,7 +58,7 @@ class ServerSKeyResponsePacket(input: DataInputStream) : ServerPacket(input) {
|
|||||||
fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket {
|
fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket {
|
||||||
this.input goto 14
|
this.input goto 14
|
||||||
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
|
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
|
||||||
return ServerSKeyResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
|
return ServerSKeyResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream()).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,14 @@
|
|||||||
package net.mamoe.mirai.network.packet
|
package net.mamoe.mirai.network.packet
|
||||||
|
|
||||||
|
import net.mamoe.mirai.message.FaceID
|
||||||
|
import net.mamoe.mirai.message.Message
|
||||||
|
import net.mamoe.mirai.message.defaults.Face
|
||||||
|
import net.mamoe.mirai.message.defaults.Image
|
||||||
import net.mamoe.mirai.message.defaults.MessageChain
|
import net.mamoe.mirai.message.defaults.MessageChain
|
||||||
import net.mamoe.mirai.message.defaults.PlainText
|
import net.mamoe.mirai.message.defaults.PlainText
|
||||||
import net.mamoe.mirai.network.Protocol
|
import net.mamoe.mirai.network.Protocol
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
import net.mamoe.mirai.utils.hexToBytes
|
||||||
import net.mamoe.mirai.utils.toUHexString
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
@ -39,12 +44,12 @@ open class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, va
|
|||||||
//"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity)
|
//"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity)
|
||||||
|
|
||||||
else -> UnknownServerEventPacket(this.input, packetId, eventIdentity)
|
else -> UnknownServerEventPacket(this.input, packetId, eventIdentity)
|
||||||
}
|
}.setId(this.idHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PacketId("00 17")
|
@PacketId("00 17")
|
||||||
class Encrypted(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
|
class Encrypted(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
|
||||||
fun decrypt(sessionKey: ByteArray): Raw = Raw(decryptBy(sessionKey), packetId)
|
fun decrypt(sessionKey: ByteArray): Raw = Raw(decryptBy(sessionKey), packetId).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,15 +108,15 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
|||||||
//println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00
|
//println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00
|
||||||
|
|
||||||
messageType = when (val id = this.input.goto(110 + fontLength + 2).readByte().toInt()) {
|
messageType = when (val id = this.input.goto(110 + fontLength + 2).readByte().toInt()) {
|
||||||
19 -> MessageType.NORMAL
|
0x13 -> MessageType.NORMAL
|
||||||
14 -> MessageType.XML
|
0xE -> MessageType.XML
|
||||||
6 -> MessageType.AT
|
0x06 -> MessageType.AT
|
||||||
|
|
||||||
|
|
||||||
1 -> MessageType.PLAIN_TEXT
|
0x01 -> MessageType.PLAIN_TEXT
|
||||||
2 -> MessageType.FACE
|
0x02 -> MessageType.FACE
|
||||||
3 -> MessageType.IMAGE
|
0x03 -> MessageType.IMAGE
|
||||||
25 -> MessageType.ANONYMOUS
|
0x19 -> MessageType.ANONYMOUS
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
MiraiLogger debug ("ServerGroupMessageEventPacket id=$id")
|
MiraiLogger debug ("ServerGroupMessageEventPacket id=$id")
|
||||||
@ -185,23 +190,102 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
|
|||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
override fun decode() {
|
override fun decode() {
|
||||||
//start at Sep1.0:27
|
|
||||||
input.goto(0)
|
input.goto(0)
|
||||||
|
println()
|
||||||
println(input.readAllBytes().toUHexString())
|
println(input.readAllBytes().toUHexString())
|
||||||
input.goto(0)
|
input.goto(0)
|
||||||
|
|
||||||
qq = input.readIntAt(0).toLong()
|
qq = input.readUIntAt(0).toLong()
|
||||||
val msgLength = input.readShortAt(22)
|
|
||||||
val fontLength = input.readShortAt(93 + msgLength)
|
val l1 = input.readShortAt(22)
|
||||||
val offset = msgLength + fontLength
|
input.goto(93 + l1)
|
||||||
|
input.readVarByteArray()//font
|
||||||
|
input.skip(2)//2个0x00
|
||||||
|
message = input.readSections()
|
||||||
|
println(message.toObjectString())
|
||||||
|
|
||||||
|
/*
|
||||||
|
val offset = unknownLength0 + fontLength//57
|
||||||
message = MessageChain(PlainText(let {
|
message = MessageChain(PlainText(let {
|
||||||
val offset2 = input.readShortAt(101 + offset)
|
val length = input.readShortAt(101 + offset)//
|
||||||
input.goto(103 + offset).readVarString(offset2.toInt())
|
input.goto(103 + offset).readString(length.toInt())
|
||||||
}))
|
}))*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun DataInputStream.readSection(): Message? {
|
||||||
|
val messageType = this.readByte().toInt()
|
||||||
|
val sectionLength = this.readShort().toLong()//sectionLength: short
|
||||||
|
this.skip(1)//message和face是 0x01, image是0x06
|
||||||
|
return when (messageType) {
|
||||||
|
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(readVarNumber().toInt())//可能这个是id, 也可能下面那个
|
||||||
|
this.skip(this.readByte().toLong())
|
||||||
|
this.readVarNumber()//某id?
|
||||||
|
return Face(id1)
|
||||||
|
}
|
||||||
|
0x06 -> {
|
||||||
|
this.skip(sectionLength - 37 - 1)
|
||||||
|
val imageId = String(this.readNBytes(36))
|
||||||
|
this.skip(1)//0x41
|
||||||
|
return Image(imageId)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DataInputStream.readSections(): MessageChain {
|
||||||
|
val chain = MessageChain()
|
||||||
|
var got: Message? = null
|
||||||
|
do {
|
||||||
|
if (got != null) {
|
||||||
|
chain.concat(got)
|
||||||
|
}
|
||||||
|
got = this.readSection()
|
||||||
|
} while (got != null)
|
||||||
|
return chain
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
println(String("16 20 20 39 39 31 30 20 38 38 31 43 42 20 20 20 20 20 20 31 37 36 32 65 42 39 45 32 37 32 31 43 39 36 44 37 39 41 38 32 31 36 45 30 41 44 34 30 42 35 39 35 39 31 38 36 2E 6A 70 67 66 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 41".replace(" ", " ").hexToBytes()))
|
||||||
|
println(".jpg".toByteArray().size)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
牛逼 (10404
|
||||||
|
3E 03 3F A2 8F 00 1A E5 00 0B 53 3B 64 6B 91 17 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 40 5D 73 AF A1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 AF A1 1F EE 24 55 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
牛逼 (10404
|
||||||
|
3E 03 3F A2 8F 00 1A E5 00 00 86 F3 09 18 83 47 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 41 5D 73 B3 21 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 B3 20 94 B0 82 BC 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
牛逼 (19947
|
||||||
|
76 E4 B8 DD 8F 00 1A E5 00 0D A2 8A 0A 65 7C D0 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 76 E4 B8 DD 8F 00 1A E5 4E 35 88 98 FE 64 7C E9 33 F7 2F B1 32 5D 5F A9 00 0B 77 FC 5D 73 B4 38 02 5B 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 B4 38 A6 60 C7 9A 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 0E 00 07 01 00 04 00 00 00 00
|
||||||
|
|
||||||
|
牛逼 (jiahua
|
||||||
|
B1 89 BE 09 8F 00 1A E5 00 0D EB CB 09 90 BA CF 1F 40 00 A6 00 00 00 20 00 05 00 02 00 01 00 06 00 04 00 01 05 0F 00 09 00 06 03 E9 20 02 E5 B3 00 0A 00 04 01 00 00 00 25 15 B1 89 BE 09 8F 00 1A E5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B 77 A3 5D 73 B4 7D 00 00 5D 73 B4 7D 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 73 B4 7D 0E A3 93 E3 00 00 00 00 09 00 86 00 00 09 48 65 6C 76 65 74 69 63 61 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00 19 00 1C 01 00 19 AA 02 16 08 00 88 01 00 9A 01 0E 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
牛逼 (jiahua
|
||||||
|
B1 89 BE 09 8F 00 1A E5 00 0B 03 A2 09 90 BB 7A 1F 40 00 A6 00 00 00 20 00 05 00 02 00 01 00 06 00 04 00 01 05 0F 00 09 00 06 03 E9 20 02 E5 B3 00 0A 00 04 01 00 00 00 25 15 B1 89 BE 09 8F 00 1A E5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B 77 A5 5D 73 B6 33 00 00 5D 73 B6 33 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 73 B6 33 22 DE A7 56 00 00 00 00 09 00 86 00 00 09 48 65 6C 76 65 74 69 63 61 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00 19 00 1C 01 00 19 AA 02 16 08 00 88 01 00 9A 01 0E 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
牛逼[EMOJI表情1]牛逼 (10404
|
||||||
|
3E 03 3F A2 8F 00 1A E5 00 0B 59 A3 64 6B 91 17 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 44 5D 73 BA D9 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 BA D9 12 C7 FC CD 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 02 00 14 01 00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
牛逼[EMOJI表情2]牛逼 (10404
|
||||||
|
3E 03 3F A2 8F 00 1A E5 00 0D 4D 4A 09 18 83 47 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 45 5D 73 BF A0 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 BF A0 68 31 43 A2 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 02 00 14 01 00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
牛逼[EMOJI表情1]牛逼 (10404
|
||||||
|
3E 03 3F A2 8F 00 1A E5 00 02 3C 8E 64 6B 91 17 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 47 5D 73 C3 76 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 C3 75 41 3B 97 72 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 0F 01 00 0C E7 89 9B E9 80 BC E7 89 9B E9 80 BC 02 00 14 01 00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
[图片] (10404
|
||||||
|
3E 03 3F A2 8F 00 1A E5 00 0E 02 CF 64 6B A0 0C 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 4B 5D 73 D1 1C 01 1D 00 00 00 00 01 00 00 00 0C 4D 53 47 00 00 00 00 00 5D 73 D1 1C F5 78 37 16 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 06 00 F0 02 00 1B 28 5A 53 41 58 40 57 4B 52 4A 5A 31 7E 33 59 4F 53 53 4C 4D 32 4B 49 2E 6A 70 67 03 00 04 00 00 06 E2 04 00 25 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 14 00 04 03 00 00 00 18 00 25 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 19 00 04 00 00 00 38 1A 00 04 00 00 00 34 FF 00 63 16 20 20 39 39 31 30 20 38 38 31 43 42 20 20 20 20 20 20 31 37 36 32 65 42 39 45 32 37 32 31 43 39 36 44 37 39 41 38 32 31 36 45 30 41 44 34 30 42 35 39 35 39 31 38 36 2E 6A 70 67 66 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 41 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 告知服务器已经收到数据
|
* 告知服务器已经收到数据
|
||||||
@ -223,6 +307,10 @@ class ClientMessageResponsePacket(
|
|||||||
it.write(eventIdentity)
|
it.write(eventIdentity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getFixedId(): String {
|
||||||
|
return packetIdFromServer.toUHexString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -253,7 +341,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
|
|||||||
//.gif
|
//.gif
|
||||||
}else {
|
}else {
|
||||||
val offset2 = input.readShortAt(101 + offset)
|
val offset2 = input.readShortAt(101 + offset)
|
||||||
input.goto(103 + offset).readVarString(offset2.toInt())
|
input.goto(103 + offset).readString(offset2.toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.mamoe.mirai.network.packet
|
package net.mamoe.mirai.network.packet
|
||||||
|
|
||||||
|
import net.mamoe.mirai.network.packet.PacketNameFormatter.adjustName
|
||||||
|
import net.mamoe.mirai.network.packet.action.ServerCanAddFriendResponsePacket
|
||||||
import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
|
import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
|
||||||
import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
|
import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
|
||||||
import net.mamoe.mirai.network.packet.login.*
|
import net.mamoe.mirai.network.packet.login.*
|
||||||
@ -10,6 +12,32 @@ import java.io.DataInputStream
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
abstract class ServerPacket(val input: DataInputStream) : Packet {
|
abstract class ServerPacket(val input: DataInputStream) : Packet {
|
||||||
|
var idHex: String
|
||||||
|
|
||||||
|
var idByteArray: ByteArray//fixed 4 size
|
||||||
|
|
||||||
|
|
||||||
|
var encoded: Boolean = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
idHex = try {
|
||||||
|
val annotation = this.javaClass.getAnnotation(PacketId::class.java)
|
||||||
|
annotation.value.trim()
|
||||||
|
} catch (e: NullPointerException) {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
idByteArray = if (idHex.isEmpty()) {
|
||||||
|
byteArrayOf(0, 0, 0, 0)
|
||||||
|
} else {
|
||||||
|
idHex.hexToBytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <P : ServerPacket> P.setId(idHex: String): P {
|
||||||
|
this.idHex = idHex
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
open fun decode() {
|
open fun decode() {
|
||||||
|
|
||||||
@ -19,34 +47,32 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
|
|||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun ofByteArray(bytes: ByteArray): ServerPacket {
|
fun ofByteArray(bytes: ByteArray): ServerPacket {
|
||||||
//println("Raw received: ${bytes.toUByteArray().toUHexString()}")
|
|
||||||
|
|
||||||
val stream = bytes.dataInputStream()
|
val stream = bytes.dataInputStream()
|
||||||
|
|
||||||
stream.skip(3)
|
stream.skip(3)
|
||||||
|
|
||||||
|
val idHex = stream.readInt().toUHexString(" ")
|
||||||
return when (val idHex = stream.readInt().toHexString(" ")) {
|
return when (idHex) {
|
||||||
"08 25 31 01" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
|
"08 25 31 01" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
|
||||||
"08 25 31 02" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
|
"08 25 31 02" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
|
||||||
|
|
||||||
"08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
|
"08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
|
||||||
when (bytes.size) {
|
when (bytes.size) {
|
||||||
271, 207 -> return ServerLoginResponseResendPacket.Encrypted(stream, when (idHex) {
|
271, 207 -> return ServerLoginResponseKeyExchangePacket.Encrypted(stream, when (idHex) {
|
||||||
"08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03`
|
"08 36 31 03" -> ServerLoginResponseKeyExchangePacket.Flag.`08 36 31 03`
|
||||||
else -> {
|
else -> ServerLoginResponseKeyExchangePacket.Flag.OTHER
|
||||||
MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER
|
|
||||||
}
|
}).apply { this.idHex = idHex }
|
||||||
})
|
871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream).apply { this.idHex = idHex }
|
||||||
871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes.size > 700) {
|
if (bytes.size > 700) {
|
||||||
return ServerLoginResponseSuccessPacket.Encrypted(stream)
|
return ServerLoginResponseSuccessPacket.Encrypted(stream).apply { this.idHex = idHex }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println(bytes.size)
|
||||||
return ServerLoginResponseFailedPacket(when (bytes.size) {
|
return ServerLoginResponseFailedPacket(when (bytes.size) {
|
||||||
319, 135 -> LoginState.WRONG_PASSWORD
|
63, 319, 135, 351 -> LoginState.WRONG_PASSWORD//这四个其中一个也是被冻结
|
||||||
//135 -> LoginState.RETYPE_PASSWORD
|
//135 -> LoginState.RETYPE_PASSWORD
|
||||||
279 -> LoginState.BLOCKED
|
279 -> LoginState.BLOCKED
|
||||||
263 -> LoginState.UNKNOWN_QQ_NUMBER
|
263 -> LoginState.UNKNOWN_QQ_NUMBER
|
||||||
@ -57,10 +83,10 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
|
|||||||
/*
|
/*
|
||||||
//unknown
|
//unknown
|
||||||
63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")
|
63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")
|
||||||
351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data or Unknown error)")//包数据有误
|
351 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")
|
||||||
|
|
||||||
else -> throw IllegalArgumentException(bytes.size.toString())*/
|
else -> throw IllegalArgumentException(bytes.size.toString())*/
|
||||||
}, stream)
|
}, stream).apply { this.idHex = idHex }
|
||||||
}
|
}
|
||||||
|
|
||||||
"08 28 04 34" -> ServerSessionKeyResponsePacket.Encrypted(stream)
|
"08 28 04 34" -> ServerSessionKeyResponsePacket.Encrypted(stream)
|
||||||
@ -83,15 +109,18 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
|
|||||||
"00 CD" -> ServerSendFriendMessageResponsePacket(stream)
|
"00 CD" -> ServerSendFriendMessageResponsePacket(stream)
|
||||||
"00 02" -> ServerSendGroupMessageResponsePacket(stream)
|
"00 02" -> ServerSendGroupMessageResponsePacket(stream)
|
||||||
|
|
||||||
|
"00 A7" -> ServerCanAddFriendResponsePacket(stream)
|
||||||
|
|
||||||
else -> throw IllegalArgumentException(idHex)
|
else -> throw IllegalArgumentException(idHex)
|
||||||
}
|
}
|
||||||
}
|
}.apply { this.idHex = idHex }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return this.javaClass.simpleName + this.getAllDeclaredFields().joinToString(", \n", "{", "}") {
|
return adjustName(this.javaClass.simpleName + "(${this.getFixedId()})") + this.getAllDeclaredFields().filterNot { it.name == "idHex" || it.name == "encoded" }.joinToString(", ", "{", "}") {
|
||||||
it.trySetAccessible(); it.name + "=" + it.get(this).let { value ->
|
it.trySetAccessible(); it.name + "=" + it.get(this).let { value ->
|
||||||
when (value) {
|
when (value) {
|
||||||
is ByteArray -> value.toUHexString()
|
is ByteArray -> value.toUHexString()
|
||||||
@ -102,15 +131,48 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun getFixedId(): String = getFixedId(this.idHex)
|
||||||
|
|
||||||
|
fun getFixedId(id: String): String = when (id.length) {
|
||||||
|
0 -> "__ __ __ __"
|
||||||
|
2 -> "$id __ __ __"
|
||||||
|
5 -> "$id __ __"
|
||||||
|
7 -> "$id __"
|
||||||
|
else -> id
|
||||||
|
}
|
||||||
|
|
||||||
fun decryptBy(key: ByteArray): DataInputStream {
|
fun decryptBy(key: ByteArray): DataInputStream {
|
||||||
input.goto(14)
|
return decryptAsByteArray(key).dataInputStream()
|
||||||
return DataInputStream(TEA.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, key).inputStream())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun decryptBy(keyHex: String): DataInputStream {
|
fun decryptBy(keyHex: String): DataInputStream {
|
||||||
return this.decryptBy(keyHex.hexToBytes())
|
return this.decryptBy(keyHex.hexToBytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun decryptBy(key1: ByteArray, key2: ByteArray): DataInputStream {
|
||||||
|
return TEA.decrypt(this.decryptAsByteArray(key1), key2).dataInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
fun decryptBy(key1: String, key2: ByteArray): DataInputStream {
|
||||||
|
return this.decryptBy(key1.hexToBytes(), key2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
fun decryptBy(key1: ByteArray, key2: String): DataInputStream {
|
||||||
|
return this.decryptBy(key1, key2.hexToBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
fun decryptBy(keyHex1: String, keyHex2: String): DataInputStream {
|
||||||
|
return this.decryptBy(keyHex1.hexToBytes(), keyHex2.hexToBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decryptAsByteArray(key: ByteArray): ByteArray {
|
||||||
|
input.goto(14)
|
||||||
|
return TEA.decrypt(input.readAllBytes().cutTail(1), key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,11 +187,15 @@ fun DataInputStream.readIP(): String {
|
|||||||
return buff
|
return buff
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DataInputStream.readShortVarString(): String {
|
fun DataInputStream.readVarString(): String {
|
||||||
return String(this.readNBytes(this.readShort().toInt()))
|
return String(this.readVarByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DataInputStream.readVarString(length: Int): String {
|
fun DataInputStream.readVarByteArray(): ByteArray {
|
||||||
|
return this.readNBytes(this.readShort().toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DataInputStream.readString(length: Int): String {
|
||||||
return String(this.readNBytes(length))
|
return String(this.readNBytes(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,6 +220,17 @@ fun <N : Number> DataInputStream.readNBytes(length: N): ByteArray {
|
|||||||
return this.readNBytes(length.toInt())
|
return this.readNBytes(length.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun DataInputStream.readVarNumber(): Number {
|
||||||
|
return when (this.readShort().toInt()) {
|
||||||
|
1 -> this.readByte()
|
||||||
|
2 -> this.readShort()
|
||||||
|
4 -> this.readInt()
|
||||||
|
8 -> this.readLong()
|
||||||
|
else -> throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun DataInputStream.readNBytesIn(range: IntRange): ByteArray {
|
fun DataInputStream.readNBytesIn(range: IntRange): ByteArray {
|
||||||
this.goto(range.first)
|
this.goto(range.first)
|
||||||
return this.readNBytes(range.last - range.first + 1)
|
return this.readNBytes(range.last - range.first + 1)
|
||||||
@ -164,6 +241,12 @@ fun <N : Number> DataInputStream.readIntAt(position: N): Int {
|
|||||||
return this.readInt();
|
return this.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
fun <N : Number> DataInputStream.readUIntAt(position: N): UInt {
|
||||||
|
this.goto(position)
|
||||||
|
return this.readNBytes(4).toUInt();
|
||||||
|
}
|
||||||
|
|
||||||
fun <N : Number> DataInputStream.readByteAt(position: N): Byte {
|
fun <N : Number> DataInputStream.readByteAt(position: N): Byte {
|
||||||
this.goto(position)
|
this.goto(position)
|
||||||
return this.readByte();
|
return this.readByte();
|
||||||
|
@ -107,7 +107,7 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d
|
|||||||
fun decrypt(sessionResponseDecryptionKey: ByteArray): ServerSessionKeyResponsePacket {
|
fun decrypt(sessionResponseDecryptionKey: ByteArray): ServerSessionKeyResponsePacket {
|
||||||
this.input goto 14
|
this.input goto 14
|
||||||
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
|
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
|
||||||
return ServerSessionKeyResponsePacket(TEA.decrypt(data, sessionResponseDecryptionKey).dataInputStream(), data.size)
|
return ServerSessionKeyResponsePacket(TEA.decrypt(data, sessionResponseDecryptionKey).dataInputStream(), data.size).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,10 @@
|
|||||||
package net.mamoe.mirai.network.packet
|
package net.mamoe.mirai.network.packet
|
||||||
|
|
||||||
import net.mamoe.mirai.network.Protocol
|
import net.mamoe.mirai.network.Protocol
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.ByteArrayDataOutputStream
|
||||||
|
import net.mamoe.mirai.utils.TEA
|
||||||
|
import net.mamoe.mirai.utils.hexToBytes
|
||||||
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@ -13,13 +16,13 @@ import java.io.IOException
|
|||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
|
@PacketId("08 25 31 01")
|
||||||
class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inputStream) {
|
class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inputStream) {
|
||||||
var serverIP: String? = null;
|
var serverIP: String? = null
|
||||||
|
|
||||||
var loginTime: Int = 0
|
var loginTime: Int = 0
|
||||||
lateinit var loginIP: String
|
lateinit var loginIP: String
|
||||||
lateinit var token0825: ByteArray
|
lateinit var token0825: ByteArray
|
||||||
lateinit var tgtgtKey: ByteArray
|
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
TYPE_08_25_31_01,
|
TYPE_08_25_31_01,
|
||||||
@ -40,7 +43,6 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
|
|||||||
|
|
||||||
loginTime = input.readInt()
|
loginTime = input.readInt()
|
||||||
loginIP = input.readIP()
|
loginIP = input.readIP()
|
||||||
tgtgtKey = getRandomByteArray(16)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
@ -54,7 +56,7 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
|
|||||||
fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) {
|
fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) {
|
||||||
Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
|
Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
|
||||||
Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes()
|
Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes()
|
||||||
}))
|
})).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +85,6 @@ class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() {
|
|||||||
this.writeIP(serverIp);
|
this.writeIP(serverIp);
|
||||||
this.writeHex("00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19")
|
this.writeHex("00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19")
|
||||||
this.writeHex(Protocol.publicKey)
|
this.writeHex(Protocol.publicKey)
|
||||||
println(super.toUByteArray().toUHexString())
|
|
||||||
return super.toByteArray()
|
return super.toByteArray()
|
||||||
}
|
}
|
||||||
}.toByteArray()))
|
}.toByteArray()))
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package net.mamoe.mirai.network.packet
|
package net.mamoe.mirai.network.packet
|
||||||
|
|
||||||
import net.mamoe.mirai.network.Protocol
|
import net.mamoe.mirai.network.Protocol
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.*
|
||||||
import net.mamoe.mirai.utils.TEA
|
|
||||||
import net.mamoe.mirai.utils.TestedSuccessfully
|
|
||||||
import net.mamoe.mirai.utils.hexToBytes
|
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,7 +10,7 @@ import java.io.DataInputStream
|
|||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
@PacketId("00 BA 31")
|
@PacketId("00 BA 31")
|
||||||
class ClientVerificationCodeTransmissionRequestPacket(
|
class ClientVerificationCodeTransmissionRequestPacket(
|
||||||
private val verificationSessionId: Int,
|
private val packetId: Int,
|
||||||
private val qq: Long,
|
private val qq: Long,
|
||||||
private val token0825: ByteArray,
|
private val token0825: ByteArray,
|
||||||
private val verificationSequence: Int,
|
private val verificationSequence: Int,
|
||||||
@ -21,10 +18,10 @@ class ClientVerificationCodeTransmissionRequestPacket(
|
|||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
@TestedSuccessfully
|
@TestedSuccessfully
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
MiraiLogger debug "verificationSessionId=$verificationSessionId"
|
MiraiLogger debug "packetId=$packetId"
|
||||||
MiraiLogger debug "verificationSequence=$verificationSequence"
|
MiraiLogger debug "verificationSequence=$verificationSequence"
|
||||||
|
|
||||||
this.writeByte(verificationSessionId)//part of packet id
|
this.writeByte(packetId)//part of packet id
|
||||||
|
|
||||||
this.writeQQ(qq)
|
this.writeQQ(qq)
|
||||||
this.writeHex(Protocol.fixVer)
|
this.writeHex(Protocol.fixVer)
|
||||||
@ -52,14 +49,18 @@ class ClientVerificationCodeTransmissionRequestPacket(
|
|||||||
@PacketId("00 BA 32")
|
@PacketId("00 BA 32")
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class ClientVerificationCodeSubmitPacket(
|
class ClientVerificationCodeSubmitPacket(
|
||||||
|
private val packetIdLast: Int,
|
||||||
private val qq: Long,
|
private val qq: Long,
|
||||||
private val token0825: ByteArray,
|
private val token0825: ByteArray,
|
||||||
private val verificationSessionId: Int,
|
|
||||||
private val verificationCode: String,
|
private val verificationCode: String,
|
||||||
private val verificationToken: ByteArray
|
private val verificationToken: ByteArray
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
|
init {
|
||||||
|
require(verificationCode.length == 4) { "verificationCode.length must == 4" }
|
||||||
|
}
|
||||||
|
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
this.writeByte(verificationSessionId)//part of packet id
|
this.writeByte(packetIdLast)//part of packet id
|
||||||
|
|
||||||
this.writeQQ(qq)
|
this.writeQQ(qq)
|
||||||
this.writeHex(Protocol.fixVer)
|
this.writeHex(Protocol.fixVer)
|
||||||
@ -69,17 +70,51 @@ class ClientVerificationCodeSubmitPacket(
|
|||||||
it.writeHex(Protocol.constantData2)
|
it.writeHex(Protocol.constantData2)
|
||||||
it.writeHex("01 00 38")
|
it.writeHex("01 00 38")
|
||||||
it.write(token0825)
|
it.write(token0825)
|
||||||
it.writeHex("01 03 00 19")
|
it.writeHex("01 03")
|
||||||
|
|
||||||
|
it.writeShort(25)
|
||||||
it.writeHex(Protocol.publicKey)
|
it.writeHex(Protocol.publicKey)
|
||||||
|
|
||||||
it.writeHex("14 00 05 00 00 00 00 00 04")
|
it.writeHex("14 00 05 00 00 00 00 00 04")
|
||||||
it.write(verificationCode.substring(0..3).toByteArray())
|
it.write(verificationCode.toUpperCase().toByteArray())
|
||||||
it.writeByte(0x38)
|
it.writeHex("00 38")
|
||||||
it.write(verificationToken)
|
it.write(verificationToken)
|
||||||
|
|
||||||
it.writeHex("00 10")
|
it.writeHex("00 10")
|
||||||
it.writeHex(Protocol.key00BAFix)
|
it.writeHex(Protocol.key00BAFix)
|
||||||
}
|
}
|
||||||
this.writeHex("")
|
}
|
||||||
|
|
||||||
|
override fun getFixedId(): String {
|
||||||
|
return this.idHex + " " + packetIdLast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
fun main() {
|
||||||
|
val token0825 = "6E AF F9 2C 20 2B DE 21 B6 13 6F 26 43 F4 04 7B 1F 88 08 4E 8E BE E5 D1 3F E7 93 DE DD E0 6E 38 65 C7 C7 D3 20 7D AC 73 AD F9 85 F9 CC 2A 2C 26 C6 B1 5B FD 34 3F D4 F2".hexToBytes()
|
||||||
|
val verificationCode = "AAAA"
|
||||||
|
val verificationToken = "84 2D 1D 9D 07 04 34 80 17 9E 3F 58 02 20 9A 1C 22 D0 73 7D 8A 90 1B 2F F8 E6 79 A6 84 2F 98 F5 1E 66 3D 9A 24 59 18 34 42 BD 45 DA E1 22 2D BC 2D 36 80 86 AD 44 C2 94".hexToBytes()
|
||||||
|
//00 02 00 00 08 04 01 E0 00 00 04 53 00 00 00 01 00 00 15 85 01 00 38 6E AF F9 2C 20 2B DE 21 B6 13 6F 26 43 F4 04 7B 1F 88 08 4E 8E BE E5 D1 3F E7 93 DE DD E0 6E 38 65 C7 C7 D3 20 7D AC 73 AD F9 85 F9 CC 2A 2C 26 C6 B1 5B FD 34 3F D4 F2 01 03 00 19 02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3 14 00 05 00 00 00 00 00 04 58 51 4E 44 00 38 84 2D 1D 9D 07 04 34 80 17 9E 3F 58 02 20 9A 1C 22 D0 73 7D 8A 90 1B 2F F8 E6 79 A6 84 2F 98 F5 1E 66 3D 9A 24 59 18 34 42 BD 45 DA E1 22 2D BC 2D 36 80 86 AD 44 C2 94 00 10 69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A
|
||||||
|
ByteArrayDataOutputStream().let {
|
||||||
|
it.writeHex("00 02 00 00 08 04 01 E0")
|
||||||
|
it.writeHex(Protocol.constantData2)
|
||||||
|
it.writeHex("01 00 38")
|
||||||
|
it.write(token0825)
|
||||||
|
it.writeHex("01 03")
|
||||||
|
|
||||||
|
it.writeShort(25)
|
||||||
|
it.writeHex(Protocol.publicKey)
|
||||||
|
|
||||||
|
it.writeHex("14 00 05 00 00 00 00 00 04")
|
||||||
|
it.write(verificationCode.substring(0..3).toByteArray())
|
||||||
|
it.writeHex("00 38")
|
||||||
|
it.write(verificationToken)
|
||||||
|
|
||||||
|
it.writeHex("00 10")
|
||||||
|
it.writeHex(Protocol.key00BAFix)
|
||||||
|
|
||||||
|
println(it.toByteArray().toUHexString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,12 +124,12 @@ class ClientVerificationCodeSubmitPacket(
|
|||||||
@PacketId("00 BA 31")
|
@PacketId("00 BA 31")
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class ClientVerificationCodeRefreshPacket(
|
class ClientVerificationCodeRefreshPacket(
|
||||||
|
private val packetIdLast: Int,
|
||||||
private val qq: Long,
|
private val qq: Long,
|
||||||
private val token0825: ByteArray,
|
private val token0825: ByteArray
|
||||||
private val verificationSessionId: Int
|
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
this.writeByte(verificationSessionId)//part of packet id
|
this.writeByte(packetIdLast)//part of packet id
|
||||||
|
|
||||||
this.writeQQ(qq)
|
this.writeQQ(qq)
|
||||||
this.writeHex(Protocol.fixVer)
|
this.writeHex(Protocol.fixVer)
|
||||||
@ -109,16 +144,18 @@ class ClientVerificationCodeRefreshPacket(
|
|||||||
it.writeHex("13 00 05 00 00 00 00 00 00 00 00 10")
|
it.writeHex("13 00 05 00 00 00 00 00 00 00 00 10")
|
||||||
it.writeHex(Protocol.key00BAFix)
|
it.writeHex(Protocol.key00BAFix)
|
||||||
}
|
}
|
||||||
this.writeHex("")
|
}
|
||||||
|
|
||||||
|
override fun getFixedId(): String {
|
||||||
|
return this.idHex + " " + packetIdLast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码输入错误
|
* 验证码输入错误
|
||||||
*/
|
*/
|
||||||
class ServerVerificationCodeWrongPacket(input: DataInputStream, dataSize: Int, packetId: ByteArray) : ServerVerificationCodeTransmissionPacket(input, dataSize, packetId) {
|
@PacketId("00 BA 32")
|
||||||
|
class ServerVerificationCodeWrongPacket(input: DataInputStream, dataSize: Int, packetId: ByteArray) : ServerVerificationCodeTransmissionPacket(input, dataSize, packetId)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器发送验证码图片文件一部分过来
|
* 服务器发送验证码图片文件一部分过来
|
||||||
@ -128,42 +165,47 @@ class ServerVerificationCodeWrongPacket(input: DataInputStream, dataSize: Int, p
|
|||||||
@PacketId("00 BA 31")
|
@PacketId("00 BA 31")
|
||||||
open class ServerVerificationCodeTransmissionPacket(input: DataInputStream, private val dataSize: Int, private val packetId: ByteArray) : ServerVerificationCodePacket(input) {
|
open class ServerVerificationCodeTransmissionPacket(input: DataInputStream, private val dataSize: Int, private val packetId: ByteArray) : ServerVerificationCodePacket(input) {
|
||||||
|
|
||||||
lateinit var verificationCodePartN: ByteArray
|
lateinit var captchaSectionN: ByteArray
|
||||||
lateinit var verificationToken: ByteArray//56bytes
|
lateinit var verificationToken: ByteArray//56bytes
|
||||||
var transmissionCompleted: Boolean = false//验证码是否已经传输完成
|
var transmissionCompleted: Boolean = false//验证码是否已经传输完成
|
||||||
lateinit var token00BA: ByteArray//40 bytes
|
lateinit var token00BA: ByteArray//40 bytes
|
||||||
var verificationSessionId: Int = 0
|
var packetIdLast: Int = 0
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
override fun decode() {
|
override fun decode() {
|
||||||
this.verificationToken = this.input.readNBytesAt(10, 56)
|
this.verificationToken = this.input.readNBytesAt(10, 56)
|
||||||
|
|
||||||
val length = this.input.readShortAt(66)
|
val length = this.input.readShortAt(66)
|
||||||
this.verificationCodePartN = this.input.readNBytes(length)
|
this.captchaSectionN = this.input.readNBytes(length)
|
||||||
|
|
||||||
this.input.skip(1)
|
this.input.skip(1)
|
||||||
val byte = this.input.readByteAt(69 + length).toInt()
|
val byte = this.input.readByteAt(69 + length).toInt()
|
||||||
this.transmissionCompleted = byte == 0
|
this.transmissionCompleted = byte == 0
|
||||||
|
|
||||||
this.token00BA = this.input.readNBytesAt(dataSize - 56 - 2, 40)
|
this.token00BA = this.input.readNBytesAt(dataSize - 56 - 2, 40)
|
||||||
this.verificationSessionId = packetId[3].toInt()
|
this.packetIdLast = packetId[3].toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFixedId(): String {
|
||||||
|
return this.idHex + " " + packetIdLast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fun main() {
|
fun main() {
|
||||||
val data = "13 00 05 01 00 00 01 23 00 38 41 8A 4F 49 BF 68 90 72 9E F6 DB 2A 85 12 81 BF 95 0A 64 60 3C 1A 12 20 41 74 CA BC B8 C3 0D 48 28 7B F6 C1 D2 7D B3 3D E2 12 FA 64 58 9C 79 9A 8B 6A 58 14 6C 86 25 6B 02 BC F5 EE 11 59 90 F9 12 46 D1 B0 14 DF CE DB 34 CD 0E 4C 62 5B D7 7D D7 A2 F3 51 AB EB 8B E0 CE 5C 32 A6 8A D3 D6 1D 44 22 1D E8 38 E8 F5 03 E0 91 E9 56 FB 55 91 20 36 89 F7 10 B3 ED A9 D9 11 F7 2A AB 4D 0E 6D DE 8F A1 AE A5 6F D2 91 CE D3 58 D8 04 3E BF 2C D3 3E 13 12 08 18 A8 92 F2 0D 32 40 79 B6 07 40 83 F6 6A 28 BD 94 0C 31 EA E1 C4 A3 11 46 8D 48 C8 7A E2 4E 4F 20 24 EC 48 9A 2D 14 FE 66 90 ED 8E 8A 7F D7 6D 08 64 46 90 82 37 65 A2 0C 4D 64 DC 2F AC 1F D4 9F D7 54 61 34 34 35 2A B0 CE B1 64 62 24 6B A5 33 C4 B4 9C 26 10 B6 0E 0C DA EC 20 70 43 DC 3C FB A5 A9 E3 61 49 0D A2 0F C6 DC B1 20 A7 DE 42 83 9F 48 C2 C3 98 7D 6D 3C F3 53 86 58 D6 5A 4D 0A 52 A3 39 6A FE 41 A9 9C FB C8 7A 63 1A 40 06 58 EE D7 BA 62 29 CB 9A BC 72 6B D2 FD B9 3C 94 B4 42 BE F4 F8 BD F7 06 50 9E 64 E0 27 FD 62 53 5A AA 7A C9 5C DA B2 5E BC F2 40 05 98 D8 30 74 47 9A E3 BA 85 CE 5B CC DF 3F C7 1F 0D 9E B2 03 59 6B C1 4B 75 4E C5 F3 E9 E8 86 28 D6 FC A9 1C A3 25 DF 78 91 39 8B BB 66 B5 AA FF 53 D3 0B 7D 93 A8 EF 96 70 E9 3B D3 CB 66 99 B0 33 33 62 DB D3 44 02 77 3A 26 ED 2B ED 19 98 8A 25 39 7B 9B 0B D4 26 FA AC 77 83 76 DF 22 F3 EF 37 3C 16 A6 19 9F 73 65 C4 56 5F E6 D2 E3 A9 BC F5 1A 57 F5 D0 A0 09 CA 8A 70 F1 97 41 AD 36 C1 74 B2 9A F0 FE 6B C6 B5 86 1D C2 F6 7B BE 4B 2B A3 C0 B3 14 9C B3 9E D8 D9 C8 05 A3 55 02 92 34 2F C5 52 5C 44 E3 6B 31 B8 73 3F 34 21 5D 5D EF 7D 10 EF 19 F6 45 2E C2 EE 1F 47 81 7C 9B BA 99 5D 40 0F A3 05 12 00 B8 9E FC CA 7A 50 8F 90 1D F1 D4 27 6F F6 4B 41 D6 39 A1 3A 91 0C 7D 8B 17 0D D7 F6 42 EA D1 6D 55 F8 34 C2 A5 D2 F1 1E A5 C1 1A 95 A3 7C 95 E0 D4 E5 00 5F D3 D0 33 43 F6 FA 0E 26 D4 04 2B 9B 87 71 9E 77 4D 3F E7 DC 63 2A 72 47 38 94 58 57 DA 93 B4 A8 1D A0 9D 9F 35 68 54 A3 DE 50 74 87 38 CD 08 CE 35 BE E3 50 13 C1 8C F3 09 D7 BD 70 A1 A7 33 C6 A5 1E FC 17 9F 93 FA 77 2F EF EE 6D 89 B0 96 0F 49 30 53 81 BB 2A E7 5C CD BD 98 65 3D E1 75 E7 06 77 E3 F9 45 EF E0 52 48 75 2D 52 55 01 70 5D 11 C2 A7 1B CC 81 46 E9 B4 E1 E5 CB 3E 47 89 5F 3F 47 AA 3B 1D 7D 2A 30 FE 6F EC 03 59 BA F1 0E 09 7D 4F B5 9D AB FF DB F5 B4 26 1B 40 F5 BE FF 03 E7 64 A0 DE A1 0C 6B 62 39 1F 01 01 00 28 57 1B 29 6C A0 FD FB 82 34 7D 92 07 77 CF CE 7A C9 19 FA 46 9C 9B 0A 43 30 6F 1D EE D3 E0 46 A4 83 20 CD 0A 6C AF 1A 1E 00 10 E0 5A E1 E7 FE 45 53 0B 2B 70 68 40 CB C1 D6 7A".hexToBytes()
|
val data = "13 00 05 01 00 00 01 23 00 38 59 32 29 5A 3E 3D 2D FC F5 22 EB 9E 2D FB 9C 4F AA 06 C8 32 3D F0 3C 2C 2B BA 8D 05 C4 9B C1 74 3B 70 F1 99 90 BB 6E 3E 6F 74 48 97 D3 61 B7 04 C0 A3 F1 DF 40 A4 DC 2B 00 A2 01 2D BB BB E8 FE B8 AF B3 6F 39 7C EA E2 5B 91 BE DB 59 38 CF 58 BC F2 88 F1 09 CF 92 E9 F7 FB 13 76 C5 68 29 23 3F 8E 43 16 2E 50 D7 FA 4D C1 F7 67 EF 27 FB C6 F1 A7 25 A4 BC 45 39 3A EA B2 A5 38 02 FF 4B C9 FF EB BD 89 E5 5D B9 4A 2A BE 5F 52 F1 EB 09 29 CB 3E 66 CF EF 97 89 47 BB 6B E0 7B 4A 3E A1 BC 3F FB F2 0A 83 CB E3 EA B9 43 E1 26 88 03 0B A7 E0 B2 AD 7F 83 CC DA 74 85 83 72 08 EC D2 F9 95 05 15 05 96 F7 1C FF 00 82 C3 90 22 A4 BA 90 D5 00 00 00 00 49 45 4E 44 AE 42 60 82 03 00 00 28 EA 32 5A 85 C8 D2 73 B3 40 39 77 85 65 98 00 FE 03 A2 A5 95 B4 2F E6 79 7A DE 5A 03 10 C8 3D BF 6D 3D 8B 51 84 C2 6D 49 00 10 92 AA 69 FB C6 3D 60 5A 7A A4 AC 7A B0 71 00 36".hexToBytes()
|
||||||
ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, "00 BA 31 01".hexToBytes()).let {
|
ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, "00 BA 31 01".hexToBytes()).let {
|
||||||
it.decode()
|
it.decode()
|
||||||
println(it.toString())
|
println(it.toString())
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码正确
|
* 验证码正确
|
||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
|
@PacketId("00 BA 32")
|
||||||
class ServerVerificationCodeCorrectPacket(input: DataInputStream) : ServerVerificationCodePacket(input) {
|
class ServerVerificationCodeCorrectPacket(input: DataInputStream) : ServerVerificationCodePacket(input) {
|
||||||
|
|
||||||
lateinit var token00BA: ByteArray//56 bytes
|
lateinit var token00BA: ByteArray//56 bytes
|
||||||
@ -177,20 +219,23 @@ class ServerVerificationCodeCorrectPacket(input: DataInputStream) : ServerVerifi
|
|||||||
abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
|
abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
|
||||||
|
|
||||||
@PacketId("00 BA")
|
@PacketId("00 BA")
|
||||||
class Encrypted(input: DataInputStream, val idHex: String) : ServerPacket(input) {
|
class Encrypted(input: DataInputStream, private val id: String) : ServerPacket(input) {
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun decrypt(): ServerVerificationCodePacket {
|
fun decrypt(): ServerVerificationCodePacket {
|
||||||
this.input goto 14
|
this.input goto 14
|
||||||
val data = TEA.decrypt(this.input.readAllBytes().cutTail(1), Protocol.key00BA.hexToBytes())
|
val data = TEA.decrypt(this.input.readAllBytes().cutTail(1), Protocol.key00BA.hexToBytes())
|
||||||
if (idHex.startsWith("00 BA 32")) {
|
if (id.startsWith("00 BA 32")) {
|
||||||
if (data.size == 95) {
|
return when (data.size) {
|
||||||
ServerVerificationCodeCorrectPacket(data.dataInputStream())
|
66,
|
||||||
} else {
|
95 -> ServerVerificationCodeCorrectPacket(data.dataInputStream())
|
||||||
return ServerVerificationCodeWrongPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
|
//66 -> ServerVerificationCodeUnknownPacket(data.dataInputStream())
|
||||||
}
|
else -> return ServerVerificationCodeWrongPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
|
||||||
|
}.setId(this.idHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
|
return ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4)).setId(this.idHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getFixedId(): String = this.getFixedId(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
package net.mamoe.mirai.network.packet.action
|
||||||
|
|
||||||
|
import net.mamoe.mirai.network.Protocol
|
||||||
|
import net.mamoe.mirai.network.packet.*
|
||||||
|
import net.mamoe.mirai.utils.getRandomByteArray
|
||||||
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
|
import java.io.DataInputStream
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向服务器检查是否可添加某人为好友
|
||||||
|
*
|
||||||
|
* @author Him188moe
|
||||||
|
*/
|
||||||
|
@PacketId("00 A7")
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
class ClientCanAddFriendPacket(
|
||||||
|
val bot: Long,
|
||||||
|
val qq: Long,
|
||||||
|
val sessionKey: ByteArray
|
||||||
|
) : ClientPacket() {
|
||||||
|
val packetIdLast = getRandomByteArray(2)
|
||||||
|
|
||||||
|
override fun getFixedId(): String {
|
||||||
|
return idHex + " " + packetIdLast.toUHexString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode() {
|
||||||
|
this.write(packetIdLast)//id, 2bytes
|
||||||
|
|
||||||
|
this.writeQQ(bot)
|
||||||
|
this.writeHex(Protocol.fixVer2)
|
||||||
|
this.encryptAndWrite(sessionKey) {
|
||||||
|
it.writeQQ(qq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PacketId("00 A7")
|
||||||
|
class ServerCanAddFriendResponsePacket(input: DataInputStream) : ServerPacket(input) {
|
||||||
|
lateinit var state: State
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
ALREADY_ADDED,
|
||||||
|
REQUIRE_VERIFICATION,
|
||||||
|
NOT_REQUIRE_VERIFICATION,
|
||||||
|
FAILED,
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
override fun decode() {
|
||||||
|
val data = input.goto(0).readAllBytes()
|
||||||
|
if (data.size == 99) {
|
||||||
|
state = State.ALREADY_ADDED
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state = when (data[data.size - 1].toUInt()) {
|
||||||
|
0u -> State.NOT_REQUIRE_VERIFICATION
|
||||||
|
1u -> State.REQUIRE_VERIFICATION
|
||||||
|
99u -> State.ALREADY_ADDED
|
||||||
|
3u, 4u -> State.FAILED
|
||||||
|
else -> throw IllegalArgumentException(Arrays.toString(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PacketId("00 A7")
|
||||||
|
class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
|
||||||
|
fun decrypt(sessionKey: ByteArray): ServerCanAddFriendResponsePacket {
|
||||||
|
return ServerCanAddFriendResponsePacket(this.decryptBy(sessionKey)).setId(this.idHex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求添加好友
|
||||||
|
*/
|
||||||
|
@PacketId("00 AE")
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
class ClientAddFriendPacket(
|
||||||
|
val bot: Long,
|
||||||
|
val qq: Long,
|
||||||
|
val sessionKey: ByteArray
|
||||||
|
) : ClientPacket() {
|
||||||
|
val packetIdLast = getRandomByteArray(2)
|
||||||
|
|
||||||
|
override fun getFixedId(): String {
|
||||||
|
return idHex + " " + packetIdLast.toUHexString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode() {
|
||||||
|
this.write(packetIdLast)//id, 2bytes
|
||||||
|
|
||||||
|
this.writeQQ(bot)
|
||||||
|
this.writeHex(Protocol.fixVer2)
|
||||||
|
this.encryptAndWrite(sessionKey) {
|
||||||
|
it.writeHex("01 00 01")
|
||||||
|
it.writeQQ(qq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ServerAddFriendResponsePacket(input: DataInputStream) : ServerAddContactResponsePacket(input)
|
||||||
|
|
||||||
|
class ServerAddGroupResponsePacket(input: DataInputStream) : ServerAddContactResponsePacket(input)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加好友/群的回复
|
||||||
|
*/
|
||||||
|
open class ServerAddContactResponsePacket(input: DataInputStream) : ServerPacket(input) {
|
||||||
|
|
||||||
|
|
||||||
|
class Raw(input: DataInputStream) : ServerPacket(input) {
|
||||||
|
|
||||||
|
override fun decode() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun distribute(): ServerAddContactResponsePacket {
|
||||||
|
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Encrypted(input: DataInputStream) : ServerPacket(input) {
|
||||||
|
fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package net.mamoe.mirai.network.packet.action
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加好友结果
|
||||||
|
*/
|
||||||
|
enum class AddFriendResult {
|
||||||
|
/**
|
||||||
|
* 等待对方处理
|
||||||
|
*/
|
||||||
|
WAITING_FOR_AGREEMENT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 和对方已经是好友了
|
||||||
|
*/
|
||||||
|
ALREADY_ADDED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方设置为不添加好友等
|
||||||
|
*/
|
||||||
|
FAILED,
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.network.packet.action
|
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.Protocol
|
||||||
import net.mamoe.mirai.network.packet.*
|
import net.mamoe.mirai.network.packet.*
|
||||||
import net.mamoe.mirai.utils.lazyEncode
|
import net.mamoe.mirai.utils.lazyEncode
|
||||||
@ -11,22 +12,22 @@ import java.io.DataInputStream
|
|||||||
@PacketId("00 CD")
|
@PacketId("00 CD")
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class ClientSendFriendMessagePacket(
|
class ClientSendFriendMessagePacket(
|
||||||
private val robotQQ: Long,
|
private val botQQ: Long,
|
||||||
private val targetQQ: Long,
|
private val targetQQ: Long,
|
||||||
private val sessionKey: ByteArray,
|
private val sessionKey: ByteArray,
|
||||||
private val message: String
|
private val message: MessageChain
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
this.writeRandom(2)//part of packet id
|
this.writeRandom(2)//part of packet id
|
||||||
this.writeQQ(robotQQ)
|
this.writeQQ(botQQ)
|
||||||
this.writeHex(Protocol.fixVer2)
|
this.writeHex(Protocol.fixVer2)
|
||||||
|
|
||||||
this.encryptAndWrite(sessionKey) {
|
this.encryptAndWrite(sessionKey) {
|
||||||
it.writeQQ(robotQQ)
|
it.writeQQ(botQQ)
|
||||||
it.writeQQ(targetQQ)
|
it.writeQQ(targetQQ)
|
||||||
it.writeHex("00 00 00 08 00 01 00 04 00 00 00 00")
|
it.writeHex("00 00 00 08 00 01 00 04 00 00 00 00")
|
||||||
it.writeHex("37 0F")
|
it.writeHex("37 0F")
|
||||||
it.writeQQ(robotQQ)
|
it.writeQQ(botQQ)
|
||||||
it.writeQQ(targetQQ)
|
it.writeQQ(targetQQ)
|
||||||
it.write(md5(lazyEncode { md5Key -> md5Key.writeQQ(targetQQ); md5Key.write(sessionKey) }))
|
it.write(md5(lazyEncode { md5Key -> md5Key.writeQQ(targetQQ); md5Key.write(sessionKey) }))
|
||||||
it.writeHex("00 0B")
|
it.writeHex("00 0B")
|
||||||
@ -35,24 +36,21 @@ class ClientSendFriendMessagePacket(
|
|||||||
it.writeHex("00 00 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00")
|
it.writeHex("00 00 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00")
|
||||||
it.writeTime()
|
it.writeTime()
|
||||||
it.writeRandom(4)
|
it.writeRandom(4)
|
||||||
it.writeHex("00 00 00 00 09 00 86 00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91")
|
it.writeHex("00 00 00 00 09 00 86")
|
||||||
|
it.writeHex(Protocol.friendMessageConst1)//... 85 E9 BB 91
|
||||||
it.writeZero(2)
|
it.writeZero(2)
|
||||||
|
|
||||||
if ("[face" in message
|
|
||||||
|| ".gif]" in message
|
it.write(message.toByteArray())
|
||||||
|| ".jpg]" in message
|
|
||||||
|| ".png]" in message
|
/*
|
||||||
) {
|
|
||||||
TODO("复合消息构建")
|
|
||||||
} else {
|
|
||||||
//Plain text
|
//Plain text
|
||||||
val bytes = message.toByteArray()
|
val bytes = message.toByteArray()
|
||||||
it.writeByte(0x01)
|
it.writeByte(0x01)
|
||||||
it.writeShort(bytes.size + 3)
|
it.writeShort(bytes.size + 3)
|
||||||
it.writeByte(0x01)
|
it.writeByte(0x01)
|
||||||
it.writeShort(bytes.size)
|
it.writeShort(bytes.size)
|
||||||
it.write(bytes)
|
it.write(bytes)*/
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,13 @@ import java.io.DataInputStream
|
|||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class ClientSendGroupMessagePacket(
|
class ClientSendGroupMessagePacket(
|
||||||
private val groupId: Long,//不是 number
|
private val groupId: Long,//不是 number
|
||||||
private val robotQQ: Long,
|
private val botQQ: Long,
|
||||||
private val sessionKey: ByteArray,
|
private val sessionKey: ByteArray,
|
||||||
private val message: String
|
private val message: String
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
this.writeRandom(2)//part of packet id
|
this.writeRandom(2)//part of packet id
|
||||||
this.writeQQ(robotQQ)
|
this.writeQQ(botQQ)
|
||||||
this.writeHex(Protocol.fixVer2)
|
this.writeHex(Protocol.fixVer2)
|
||||||
|
|
||||||
this.encryptAndWrite(sessionKey) {
|
this.encryptAndWrite(sessionKey) {
|
||||||
@ -30,7 +30,7 @@ class ClientSendGroupMessagePacket(
|
|||||||
it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00")
|
it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00")
|
||||||
it.writeTime()
|
it.writeTime()
|
||||||
it.writeRandom(4)
|
it.writeRandom(4)
|
||||||
it.writeHex("00 00 00 00 09 00 86 00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91")
|
it.writeHex("Protocol.messageConst1")
|
||||||
it.writeZero(2)
|
it.writeZero(2)
|
||||||
|
|
||||||
//messages
|
//messages
|
||||||
|
@ -17,8 +17,10 @@ class ClientChangeOnlineStatusPacket(
|
|||||||
private val loginStatus: ClientLoginStatus
|
private val loginStatus: ClientLoginStatus
|
||||||
|
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
|
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
this.writeRandom(2)//part of packet id
|
this.writeRandom(2)//part of packet id
|
||||||
|
|
||||||
this.writeQQ(qq)
|
this.writeQQ(qq)
|
||||||
this.writeHex(Protocol.fixVer2)
|
this.writeHex(Protocol.fixVer2)
|
||||||
this.encryptAndWrite(sessionKey) {
|
this.encryptAndWrite(sessionKey) {
|
||||||
|
@ -2,7 +2,10 @@ package net.mamoe.mirai.network.packet.login
|
|||||||
|
|
||||||
import net.mamoe.mirai.network.Protocol
|
import net.mamoe.mirai.network.Protocol
|
||||||
import net.mamoe.mirai.network.packet.*
|
import net.mamoe.mirai.network.packet.*
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.ByteArrayDataOutputStream
|
||||||
|
import net.mamoe.mirai.utils.TEA
|
||||||
|
import net.mamoe.mirai.utils.TestedSuccessfully
|
||||||
|
import net.mamoe.mirai.utils.hexToBytes
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,15 +35,14 @@ class ClientPasswordSubmissionPacket(
|
|||||||
this.encryptAndWrite(Protocol.shareKey.hexToBytes()) {
|
this.encryptAndWrite(Protocol.shareKey.hexToBytes()) {
|
||||||
it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
|
it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
|
||||||
it.writePart2()
|
it.writePart2()
|
||||||
println(it.toByteArray().toUHexString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PacketId("08 36 31 04")
|
@PacketId("08 36 31 04")
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
|
class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null)
|
||||||
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr)
|
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006)
|
||||||
|
|
||||||
@PacketId("08 36 31 05")
|
@PacketId("08 36 31 05")
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
@ -49,8 +51,8 @@ class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, lo
|
|||||||
|
|
||||||
@PacketId("08 36 31 06")
|
@PacketId("08 36 31 06")
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
|
class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null)
|
||||||
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr)
|
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006)
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
open class ClientLoginResendPacket internal constructor(
|
open class ClientLoginResendPacket internal constructor(
|
||||||
@ -61,7 +63,7 @@ open class ClientLoginResendPacket internal constructor(
|
|||||||
val tgtgtKey: ByteArray,
|
val tgtgtKey: ByteArray,
|
||||||
val token0825: ByteArray,
|
val token0825: ByteArray,
|
||||||
val token00BA: ByteArray,
|
val token00BA: ByteArray,
|
||||||
val tlv_0006_encr: ByteArray? = null
|
val tlv0006: ByteArray? = null
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
override fun encode() {
|
override fun encode() {
|
||||||
this.writeQQ(qq)
|
this.writeQQ(qq)
|
||||||
@ -72,7 +74,7 @@ open class ClientLoginResendPacket internal constructor(
|
|||||||
|
|
||||||
this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
|
this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
|
||||||
override fun toByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv_0006_encr)
|
this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv0006)
|
||||||
|
|
||||||
this.writeHex("01 10") //tag
|
this.writeHex("01 10") //tag
|
||||||
this.writeHex("00 3C")//length
|
this.writeHex("00 3C")//length
|
||||||
@ -92,21 +94,21 @@ open class ClientLoginResendPacket internal constructor(
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) {
|
private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv0006: ByteArray? = null) {
|
||||||
|
|
||||||
//this.writeInt(System.currentTimeMillis().toInt())
|
//this.writeInt(System.currentTimeMillis().toInt())
|
||||||
this.writeHex("01 12")//tag
|
this.writeHex("01 12")//tag
|
||||||
this.writeHex("00 38")//length
|
this.writeHex("00 38")//length
|
||||||
this.write(token0825)//length
|
this.write(token0825)//length
|
||||||
this.writeHex("03 0F")//tag
|
this.writeHex("03 0F")//tag
|
||||||
this.writeDeviceName(true)//todo 随机
|
this.writeDeviceName(true)
|
||||||
|
|
||||||
this.writeHex("00 05 00 06 00 02")
|
this.writeHex("00 05 00 06 00 02")
|
||||||
this.writeQQ(qq)
|
this.writeQQ(qq)
|
||||||
this.writeHex("00 06")//tag
|
this.writeHex("00 06")//tag
|
||||||
this.writeHex("00 78")//length
|
this.writeHex("00 78")//length
|
||||||
if (tlv_0006_encr != null) {
|
if (tlv0006 != null) {
|
||||||
this.write(tlv_0006_encr)
|
this.write(tlv0006)
|
||||||
} else {
|
} else {
|
||||||
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
|
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ enum class LoginState {
|
|||||||
/**
|
/**
|
||||||
* 登录成功
|
* 登录成功
|
||||||
*/
|
*/
|
||||||
SUCCEED,
|
SUCCESS,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 密码错误
|
* 密码错误
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.network.packet.login
|
package net.mamoe.mirai.network.packet.login
|
||||||
|
|
||||||
|
import net.mamoe.mirai.network.Protocol
|
||||||
import net.mamoe.mirai.network.packet.PacketId
|
import net.mamoe.mirai.network.packet.PacketId
|
||||||
import net.mamoe.mirai.network.packet.ServerPacket
|
import net.mamoe.mirai.network.packet.ServerPacket
|
||||||
import net.mamoe.mirai.network.packet.goto
|
import net.mamoe.mirai.network.packet.goto
|
||||||
@ -7,16 +8,18 @@ import net.mamoe.mirai.utils.TestedSuccessfully
|
|||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 服务器进行加密后返回 tgtgtKey
|
||||||
|
*
|
||||||
* @author NaturalHG
|
* @author NaturalHG
|
||||||
*/
|
*/
|
||||||
@PacketId("08 36 31 03")
|
@PacketId("08 36 31 03")
|
||||||
class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) : ServerPacket(input) {
|
class ServerLoginResponseKeyExchangePacket(input: DataInputStream, val flag: Flag) : ServerPacket(input) {
|
||||||
enum class Flag {
|
enum class Flag {
|
||||||
`08 36 31 03`,
|
`08 36 31 03`,
|
||||||
OTHER,
|
OTHER,
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var _0836_tlv0006_encr: ByteArray;//120bytes
|
lateinit var tlv0006: ByteArray;//120bytes
|
||||||
var tokenUnknown: ByteArray? = null
|
var tokenUnknown: ByteArray? = null
|
||||||
lateinit var tgtgtKey: ByteArray//16bytes
|
lateinit var tgtgtKey: ByteArray//16bytes
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) :
|
|||||||
tgtgtKey = this.input.readNBytes(16)//22
|
tgtgtKey = this.input.readNBytes(16)//22
|
||||||
//this.input.skip(2)//25
|
//this.input.skip(2)//25
|
||||||
this.input.goto(25)
|
this.input.goto(25)
|
||||||
_0836_tlv0006_encr = this.input.readNBytes(120)
|
tlv0006 = this.input.readNBytes(120)
|
||||||
|
|
||||||
when (flag) {
|
when (flag) {
|
||||||
Flag.`08 36 31 03` -> {
|
Flag.`08 36 31 03` -> {
|
||||||
@ -36,14 +39,17 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) :
|
|||||||
|
|
||||||
Flag.OTHER -> {
|
Flag.OTHER -> {
|
||||||
//do nothing in this packet.
|
//do nothing in this packet.
|
||||||
//[this.token] will be set in [RobotNetworkHandler]
|
//[this.token] will be set in [BotNetworkHandler]
|
||||||
//token
|
//token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
|
class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
@TestedSuccessfully
|
@TestedSuccessfully
|
||||||
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket = ServerLoginResponseResendPacket(decryptBy(tgtgtKey), flag)
|
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseKeyExchangePacket {
|
||||||
|
return ServerLoginResponseKeyExchangePacket(this.decryptBy(Protocol.shareKey, tgtgtKey), flag).setId(this.idHex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package net.mamoe.mirai.network.packet.login
|
package net.mamoe.mirai.network.packet.login
|
||||||
|
|
||||||
import net.mamoe.mirai.network.Protocol
|
import net.mamoe.mirai.network.Protocol
|
||||||
import net.mamoe.mirai.network.packet.*
|
import net.mamoe.mirai.network.packet.ServerPacket
|
||||||
import net.mamoe.mirai.utils.TEA
|
import net.mamoe.mirai.network.packet.goto
|
||||||
|
import net.mamoe.mirai.network.packet.readNBytesAt
|
||||||
|
import net.mamoe.mirai.network.packet.readString
|
||||||
import net.mamoe.mirai.utils.TestedSuccessfully
|
import net.mamoe.mirai.utils.TestedSuccessfully
|
||||||
import net.mamoe.mirai.utils.toUHexString
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
@ -41,7 +43,7 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
|
|||||||
this.token88 = this.input.readNBytesAt(189 + msgLength, 136)
|
this.token88 = this.input.readNBytesAt(189 + msgLength, 136)
|
||||||
|
|
||||||
val nickLength = this.input.goto(624 + msgLength).readByte().toInt()
|
val nickLength = this.input.goto(624 + msgLength).readByte().toInt()
|
||||||
this.nickname = this.input.readVarString(nickLength)
|
this.nickname = this.input.readString(nickLength)
|
||||||
|
|
||||||
//this.age = this.input.goto(packetDataLength - 28).readShortAt()
|
//this.age = this.input.goto(packetDataLength - 28).readShortAt()
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
|
|||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
|
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
|
||||||
input goto 14
|
input goto 14
|
||||||
return ServerLoginResponseSuccessPacket(TEA.decrypt(TEA.decrypt(input.readAllBytes().cutTail(1), Protocol.shareKey), tgtgtKey).dataInputStream());
|
return ServerLoginResponseSuccessPacket(this.decryptBy(Protocol.shareKey, tgtgtKey)).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv
|
|||||||
fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
|
fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
|
||||||
this.input goto 14
|
this.input goto 14
|
||||||
val data = TEA.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().cutTail(1));
|
val data = TEA.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().cutTail(1));
|
||||||
return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
|
return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package net.mamoe.mirai.plugin;
|
package net.mamoe.mirai.plugin;
|
||||||
|
|
||||||
import net.mamoe.mirai.Robot;
|
import net.mamoe.mirai.Bot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件基类.
|
* 插件基类.
|
||||||
* <p>
|
* <p>
|
||||||
* 插件属于整个 Mirai, 而不是属于单个 {@link Robot}.
|
* 插件属于整个 Mirai, 而不是属于单个 {@link Bot}.
|
||||||
*
|
*
|
||||||
* @see net.mamoe.mirai.event.MiraiEventManager
|
* @see net.mamoe.mirai.event.MiraiEventManager
|
||||||
* @see net.mamoe.mirai.event.MiraiEventManagerKt
|
* @see net.mamoe.mirai.event.MiraiEventManagerKt
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.utils
|
package net.mamoe.mirai.utils
|
||||||
|
|
||||||
|
import net.mamoe.mirai.Bot
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -28,12 +29,42 @@ object MiraiLogger {
|
|||||||
this.print(e.cause.toString())*/
|
this.print(e.cause.toString())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
|
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
|
||||||
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
|
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
|
||||||
kotlin.io.println("$color[Mirai] $s : $value")
|
kotlin.io.println("$color[Mirai] $s : $value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infix fun Bot.log(o: Any?) = info(o)
|
||||||
|
infix fun Bot.println(o: Any?) = info(o)
|
||||||
|
infix fun Bot.info(o: Any?) = print(this, o.toString(), LoggerTextFormat.RESET)
|
||||||
|
|
||||||
|
infix fun Bot.error(o: Any?) = print(this, o.toString(), LoggerTextFormat.RED)
|
||||||
|
|
||||||
|
infix fun Bot.notice(o: Any?) = print(this, o.toString(), LoggerTextFormat.LIGHT_BLUE)
|
||||||
|
|
||||||
|
infix fun Bot.purple(o: Any?) = print(this, o.toString(), LoggerTextFormat.PURPLE)
|
||||||
|
|
||||||
|
infix fun Bot.cyanL(o: Any?) = print(this, o.toString(), LoggerTextFormat.LIGHT_CYAN)
|
||||||
|
|
||||||
|
infix fun Bot.success(o: Any?) = print(this, o.toString(), LoggerTextFormat.GREEN)
|
||||||
|
|
||||||
|
infix fun Bot.debug(o: Any?) = print(this, o.toString(), LoggerTextFormat.YELLOW)
|
||||||
|
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun print(bot: Bot, value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) {
|
||||||
|
val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date())
|
||||||
|
kotlin.io.println("$color[Mirai] $s #R${bot.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")
|
||||||
|
}
|
||||||
|
|
||||||
fun Any.logInfo() = MiraiLogger.info(this)
|
fun Any.logInfo() = MiraiLogger.info(this)
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ import lombok.Data;
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public final class RobotAccount {
|
public final class BotAccount {
|
||||||
public final long qqNumber;
|
public final long qqNumber;
|
||||||
public final String password;
|
public final String password;
|
||||||
|
|
||||||
public RobotAccount(long qqNumber, String password) {
|
public BotAccount(long qqNumber, String password) {
|
||||||
this.qqNumber = qqNumber;
|
this.qqNumber = qqNumber;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ public final class TEA {
|
|||||||
private static final long UINT32_MASK = 0xffffffffL;
|
private static final long UINT32_MASK = 0xffffffffL;
|
||||||
private final long[] mKey;
|
private final long[] mKey;
|
||||||
private final Random mRandom;
|
private final Random mRandom;
|
||||||
|
private final byte[] key;
|
||||||
private byte[] mOutput;
|
private byte[] mOutput;
|
||||||
private byte[] mInBlock;
|
private byte[] mInBlock;
|
||||||
private int mIndexPos;
|
private int mIndexPos;
|
||||||
@ -26,6 +27,7 @@ public final class TEA {
|
|||||||
private boolean isFirstBlock;
|
private boolean isFirstBlock;
|
||||||
|
|
||||||
public TEA(byte[] key) {
|
public TEA(byte[] key) {
|
||||||
|
this.key = key;
|
||||||
mKey = new long[4];
|
mKey = new long[4];
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
mKey[i] = pack(key, i * 4, 4);
|
mKey[i] = pack(key, i * 4, 4);
|
||||||
@ -250,6 +252,12 @@ public final class TEA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] decrypt(byte[] ciphertext) {
|
public byte[] decrypt(byte[] ciphertext) {
|
||||||
return decrypt(ciphertext, 0, ciphertext.length);
|
try {
|
||||||
|
return decrypt(ciphertext, 0, ciphertext.length);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Source: " + UtilsKt.toUHexString(ciphertext, " "));
|
||||||
|
System.out.println("Key: " + UtilsKt.toUHexString(this.key, " "));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,9 +45,6 @@ fun UByteArray.toUHexString(): String = this.toUHexString(" ")
|
|||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun Byte.toUHexString(): String = this.toUByte().toString(16)
|
fun Byte.toUHexString(): String = this.toUByte().toString(16)
|
||||||
|
|
||||||
/**
|
|
||||||
* firstly [Protocol.hexToUBytes], secondly [UByteArray.toByteArray]
|
|
||||||
*/
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun String.hexToBytes(): ByteArray = Protocol.hexToBytes(this)
|
fun String.hexToBytes(): ByteArray = Protocol.hexToBytes(this)
|
||||||
|
|
||||||
@ -55,13 +52,11 @@ fun String.hexToBytes(): ByteArray = Protocol.hexToBytes(this)
|
|||||||
fun String.hexToUBytes(): UByteArray = Protocol.hexToUBytes(this)
|
fun String.hexToUBytes(): UByteArray = Protocol.hexToUBytes(this)
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun String.hexToShort(): Short = hexToBytes().let { ((it[1].toInt() shl 8) + it[0]).toShort() }
|
fun String.hexToInt(): Int = hexToBytes().toUInt().toInt()
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun String.hexToInt(): Int = hexToBytes().let { ((it[0].toInt() shl 24) + (it[1].toInt() shl 16) + (it[2].toInt() shl 8) + it[3]) }
|
fun ByteArray.toUInt(): UInt =
|
||||||
|
this[0].toUInt().and(255u).shl(24) + this[1].toUInt().and(255u).shl(16) + this[2].toUInt().and(255u).shl(8) + this[3].toUInt().and(255u).shl(0)
|
||||||
@ExperimentalUnsignedTypes
|
|
||||||
fun String.hexToByte(): Byte = hexToBytes()[0]
|
|
||||||
|
|
||||||
open class ByteArrayDataOutputStream : DataOutputStream(ByteArrayOutputStream()) {
|
open class ByteArrayDataOutputStream : DataOutputStream(ByteArrayOutputStream()) {
|
||||||
open fun toByteArray(): ByteArray = (out as ByteArrayOutputStream).toByteArray()
|
open fun toByteArray(): ByteArray = (out as ByteArrayOutputStream).toByteArray()
|
||||||
@ -101,8 +96,6 @@ internal fun getCrc32(key: ByteArray): Int = CRC32().let { it.update(key); it.va
|
|||||||
* 相当于将这个类和它所有父类的 [Class.getDeclaredFields] 都合并成一个 [List] <br></br>
|
* 相当于将这个类和它所有父类的 [Class.getDeclaredFields] 都合并成一个 [List] <br></br>
|
||||||
* 不会排除重名的字段. <br></br>
|
* 不会排除重名的字段. <br></br>
|
||||||
*
|
*
|
||||||
* @param clazz class
|
|
||||||
*
|
|
||||||
* @return field list
|
* @return field list
|
||||||
*/
|
*/
|
||||||
@Throws(SecurityException::class)
|
@Throws(SecurityException::class)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import net.mamoe.mirai.Robot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.network.packet.login.LoginState
|
import net.mamoe.mirai.network.packet.login.LoginState
|
||||||
import net.mamoe.mirai.utils.RobotAccount
|
import net.mamoe.mirai.utils.BotAccount
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,21 +64,21 @@ val qqList = "2535777366----abc123456\n" +
|
|||||||
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val goodRobotList = Collections.synchronizedList(mutableListOf<Robot>())
|
val goodBotList = Collections.synchronizedList(mutableListOf<Bot>())
|
||||||
|
|
||||||
qqList.split("\n").forEach {
|
qqList.split("\n").forEach {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val strings = it.split("----")
|
val strings = it.split("----")
|
||||||
val robot = Robot(RobotAccount(strings[0].toLong(), strings[1].let { password ->
|
val bot = Bot(BotAccount(strings[0].toLong(), strings[1].let { password ->
|
||||||
if (password.endsWith(".")) {
|
if (password.endsWith(".")) {
|
||||||
return@let password.substring(0, password.length - 1)
|
return@let password.substring(0, password.length - 1)
|
||||||
}
|
}
|
||||||
return@let password
|
return@let password
|
||||||
}), listOf())
|
}), listOf())
|
||||||
|
|
||||||
robot.network.tryLogin().whenComplete { state, _ ->
|
bot.network.tryLogin().whenComplete { state, _ ->
|
||||||
if (!(state == LoginState.BLOCKED || state == LoginState.DEVICE_LOCK || state == LoginState.WRONG_PASSWORD)) {
|
if (!(state == LoginState.BLOCKED || state == LoginState.DEVICE_LOCK || state == LoginState.WRONG_PASSWORD)) {
|
||||||
goodRobotList.add(robot)
|
goodBotList.add(bot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,6 +86,5 @@ fun main() {
|
|||||||
|
|
||||||
Thread.sleep(9 * 3000)
|
Thread.sleep(9 * 3000)
|
||||||
|
|
||||||
println(goodRobotList.joinToString("\n") { it.account.qqNumber.toString() + " " + it.account.password })
|
println(goodBotList.joinToString("\n") { it.account.qqNumber.toString() + " " + it.account.password })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +50,20 @@ public class HexComparator {
|
|||||||
|
|
||||||
@SuppressWarnings({"unused", "NonAsciiCharacters"})
|
@SuppressWarnings({"unused", "NonAsciiCharacters"})
|
||||||
private static class TestConsts {
|
private static class TestConsts {
|
||||||
private static final String 牛逼 = UtilsKt.toUHexString("牛逼".getBytes(), " ");
|
private static final String NIU_BI = UtilsKt.toUHexString("牛逼".getBytes(), " ");
|
||||||
private static final String _1994701021 = ClientPacketKt.toHexString(1994701021, " ");
|
private static final String _1994701021 = ClientPacketKt.toUHexString(1994701021, " ");
|
||||||
private static final String _1040400290 = ClientPacketKt.toHexString(1040400290, " ");
|
private static final String _1040400290 = ClientPacketKt.toUHexString(1040400290, " ");
|
||||||
private static final String _580266363 = ClientPacketKt.toHexString(580266363, " ");
|
private static final String _580266363 = ClientPacketKt.toUHexString(580266363, " ");
|
||||||
|
|
||||||
|
private static final String _1040400290_ = "3E 03 3F A2";
|
||||||
|
private static final String _1994701021_ = "76 E4 B8 DD";
|
||||||
|
private static final String _jiahua_ = "B1 89 BE 09";
|
||||||
|
|
||||||
|
private static final String SINGLE_PLAIN_MESSAGE_HEAD = "00 00 01 00 09 01";
|
||||||
|
|
||||||
|
private static final String MESSAGE_TAIL_10404 = "0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00".replace(" ", " ");
|
||||||
|
//private static final String MESSAGE_TAIL2_10404 ="".replace(" ", " ");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<Match> matches = new LinkedList<>();
|
private final List<Match> matches = new LinkedList<>();
|
||||||
@ -88,7 +98,7 @@ public class HexComparator {
|
|||||||
return new LinkedList<>();
|
return new LinkedList<>();
|
||||||
}
|
}
|
||||||
return new LinkedList<>() {{
|
return new LinkedList<>() {{
|
||||||
int index = 0;
|
int index = -1;
|
||||||
while ((index = hex.indexOf(constValue, index + 1)) != -1) {
|
while ((index = hex.indexOf(constValue, index + 1)) != -1) {
|
||||||
add(new IntRange(index / 3, (index + constValue.length()) / 3));
|
add(new IntRange(index / 3, (index + constValue.length()) / 3));
|
||||||
}
|
}
|
||||||
@ -105,18 +115,20 @@ public class HexComparator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void buildConstNameChain(int length, ConstMatcher constMatcher, StringBuilder constNameBuilder) {
|
private static void buildConstNameChain(int length, ConstMatcher constMatcher, StringBuilder constNameBuilder) {
|
||||||
|
//System.out.println(constMatcher.matches);
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
constNameBuilder.append(" ");
|
constNameBuilder.append(" ");
|
||||||
String match = constMatcher.getMatchedConstName(i / 4);
|
String match = constMatcher.getMatchedConstName(i / 4);
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
int appendedNameLength = match.length();
|
int appendedNameLength = match.length();
|
||||||
constNameBuilder.append(match);
|
constNameBuilder.append(match);
|
||||||
while (constMatcher.getMatchedConstName(i++ / 4) != null) {
|
while (match.equals(constMatcher.getMatchedConstName(i++ / 4))) {
|
||||||
if (appendedNameLength-- <= 0) {
|
if (appendedNameLength-- < 0) {
|
||||||
constNameBuilder.append(" ");
|
constNameBuilder.append(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constNameBuilder.append(" ".repeat(match.length() % 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,10 +293,10 @@ public class HexComparator {
|
|||||||
System.out.println(HexComparator.compare(
|
System.out.println(HexComparator.compare(
|
||||||
//mirai
|
//mirai
|
||||||
|
|
||||||
"2A 22 96 29 7B 00 40 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 EC 21 40 06 18 89 54 BC 00 00 00 00 09 00 86 00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 0A 01 00 07 E7 89 9B E9 80 BC 21\n"
|
"2A 22 96 29 7B 00 40 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 EC 21 40 06 18 89 54 BC Protocol.messageConst1 00 00 01 00 0A 01 00 07 E7 89 9B E9 80 BC 21\n"
|
||||||
,
|
,
|
||||||
//e
|
//e
|
||||||
"2A 22 96 29 7B 00 3F 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 6B 8E 1A FE 39 0B FC 00 00 00 00 09 00 86 00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 0A 01 00 07 6D 65 73 73 61 67 65"
|
"2A 22 96 29 7B 00 3F 00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 6B 8E 1A FE 39 0B FC Protocol.messageConst1 00 00 01 00 0A 01 00 07 6D 65 73 73 61 67 65"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>mirai</artifactId>
|
|
||||||
<groupId>net.mamoe</groupId>
|
|
||||||
<version>1.0</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>mirai-native</artifactId>
|
|
||||||
<version>1.0</version>
|
|
||||||
</project>
|
|
@ -1,9 +0,0 @@
|
|||||||
package net.mamoe.mirai.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Him188moe
|
|
||||||
*/
|
|
||||||
public final class TeaEncryption {
|
|
||||||
|
|
||||||
public static native int Decrypt();
|
|
||||||
}
|
|
39
mirai-ui/pom.xml
Normal file
39
mirai-ui/pom.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>mirai-ui</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.mamoe</groupId>
|
||||||
|
<artifactId>mirai</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>/src/main/resources</directory>
|
||||||
|
|
||||||
|
<includes>
|
||||||
|
<include>**/*.*</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
142
pom.xml
142
pom.xml
@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>mirai-core</module>
|
<module>mirai-core</module>
|
||||||
<module>mirai-native</module>
|
<module>mirai-ui</module>
|
||||||
|
<module>mirai-console</module>
|
||||||
|
<module>mirai-api</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
@ -27,41 +29,14 @@
|
|||||||
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<kotlin.version>1.3.41</kotlin.version>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
|
||||||
<defaultGoal>package</defaultGoal>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.8.1</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.ow2.asm</groupId>
|
|
||||||
<artifactId>asm</artifactId>
|
|
||||||
<version>7.1</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok-maven-plugin</artifactId>
|
|
||||||
<version>1.18.6.0</version>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -121,7 +96,114 @@
|
|||||||
<version>0.5.2</version>
|
<version>0.5.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.12.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.yaml</groupId>
|
||||||
|
<artifactId>snakeyaml</artifactId>
|
||||||
|
<version>1.18</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-reflect</artifactId>
|
||||||
|
<version>1.3.41</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<defaultGoal>package</defaultGoal>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>7.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<configuration>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-maven-plugin</artifactId>
|
||||||
|
<version>1.18.6.0</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>2.4.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
|
<shadedClassifierName>shaded</shadedClassifierName>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-maven-plugin</artifactId>
|
||||||
|
<version>1.18.6.0</version>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>process-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<jvmTarget>1.8</jvmTarget>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
Loading…
Reference in New Issue
Block a user