mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-07 16:40:43 +08:00
Merge remote-tracking branch 'origin/master'
# Conflicts: # mirai-core/src/main/java/net/mamoe/mirai/Robot.java
This commit is contained in:
commit
1c8e5679a1
26
README.md
26
README.md
@ -3,9 +3,9 @@
|
||||
一个以<b>TIM QQ协议</b>驱动的JAVA(+Kotlin) QQ机器人服务端核心
|
||||
我们坚持免费与开源
|
||||
|
||||
项目处于快速开发阶段, 现在已经可以接受和发送群聊/好友消息.
|
||||
协议来自网络上开源项目
|
||||
一切开发旨在学习, 请勿用于非法用途
|
||||
项目处于快速开发阶段, 现在已经可以接受和发送群聊/好友消息.
|
||||
协议来自网络上开源项目
|
||||
一切开发旨在学习, 请勿用于非法用途
|
||||
|
||||
<br>
|
||||
|
||||
@ -14,8 +14,8 @@ It use protocols from <i>TIM QQ</i>, that is, it won't be affected by the close
|
||||
The project is all for <b>learning proposes</b> and still in <b>developing stage</b><br>
|
||||
|
||||
### 代码结构
|
||||
Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
|
||||
与插件相关性强(或其他在二次开发中容易接触的部分)均使用 Java 完成,
|
||||
Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
|
||||
与插件相关性强(或其他在二次开发中容易接触的部分)均使用 Java 完成,
|
||||
同时也会针对kotlin提供优化的方法调用. 例如对'+'操作符的重载: `String+BufferedImage+QQ.At+Face+URL+String+File` 将会被自动处理为String消息.
|
||||
|
||||
|
||||
@ -24,14 +24,14 @@ Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持).
|
||||
- [ ] 插件(Plugin)模块 **(Working on)**
|
||||
- [x] Network - Touch
|
||||
- [X] Network - Login
|
||||
- [X] Network - Session
|
||||
- [ ] Network - Verification Code (Low priority)
|
||||
- [X] Network - Message Receiving
|
||||
- [X] Network - Message Sending
|
||||
- [ ] Network - Events **(Working on)**
|
||||
- [ ] Robot - Friend/group list
|
||||
- [ ] Message Section **(Working on)**
|
||||
- [ ] Contact
|
||||
- [X] Network - Session
|
||||
- [ ] Network - Verification Code (Low priority)
|
||||
- [X] Network - Message Receiving
|
||||
- [X] Network - Message Sending
|
||||
- [ ] Network - Events **(Working on)**
|
||||
- [ ] Robot - Friend/group list
|
||||
- [ ] Message Section **(Working on)**
|
||||
- [ ] Contact
|
||||
|
||||
<br>
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class MiraiServer {
|
||||
MiraiConfig qqs;
|
||||
|
||||
|
||||
protected MiraiServer(){
|
||||
protected MiraiServer() {
|
||||
instance = this;
|
||||
this.onLoad();
|
||||
this.onEnable();
|
||||
@ -61,17 +61,17 @@ public class MiraiServer {
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
protected void shutdown(){
|
||||
if(this.enabled) {
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "About to shutdown Mirai");
|
||||
protected void shutdown() {
|
||||
if (this.enabled) {
|
||||
getLogger().info("About to shutdown Mirai");
|
||||
this.getEventManager().broadcastEvent(new ServerDisableEvent());
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "Data have been saved");
|
||||
getLogger().info("Data have been saved");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void onLoad(){
|
||||
private void onLoad() {
|
||||
this.parentFolder = new File(System.getProperty("user.dir"));
|
||||
this.unix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS");
|
||||
|
||||
@ -79,36 +79,36 @@ public class MiraiServer {
|
||||
this.eventManager = MiraiEventManager.getInstance();
|
||||
this.taskManager = MiraiTaskManager.getInstance();
|
||||
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + (isUnix() ? "unix" : "windows"));
|
||||
getLogger().info("About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + (isUnix() ? "unix" : "windows"));
|
||||
getLogger().info("Loading data under " + LoggerTextFormat.GREEN + this.parentFolder);
|
||||
|
||||
File setting = new File(this.parentFolder + "/Mirai.ini");
|
||||
getLogger().info("Selecting setting from " + LoggerTextFormat.GREEN + setting);
|
||||
|
||||
if(!setting.exists()){
|
||||
if (!setting.exists()) {
|
||||
this.initSetting(setting);
|
||||
}else {
|
||||
} else {
|
||||
this.setting = new MiraiSetting(setting);
|
||||
}
|
||||
|
||||
File qqs = new File(this.parentFolder + "/QQ.yml");
|
||||
getLogger().info("Reading QQ accounts from " + LoggerTextFormat.GREEN + qqs);
|
||||
if(!qqs.exists()){
|
||||
if (!qqs.exists()) {
|
||||
this.initQQConfig(qqs);
|
||||
}else {
|
||||
} else {
|
||||
this.qqs = new MiraiConfig(qqs);
|
||||
}
|
||||
if(this.qqs.isEmpty()){
|
||||
if (this.qqs.isEmpty()) {
|
||||
this.initQQConfig(qqs);
|
||||
}
|
||||
|
||||
/*
|
||||
MiraiSettingMapSection qqs = this.setting.getMapSection("qq");
|
||||
qqs.forEach((a,p) -> {
|
||||
this.getLogger().info(LoggerTextFormat.SKY_BLUE + "Finding available ports between " + "1-65536");
|
||||
this.getLogger().info("Finding available ports between " + "1-65536");
|
||||
try {
|
||||
int port = MiraiNetwork.getAvailablePort();
|
||||
this.getLogger().info(LoggerTextFormat.SKY_BLUE + "Listening on port " + port);
|
||||
this.getLogger().info("Listening on port " + port);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -178,56 +178,56 @@ public class MiraiServer {
|
||||
}
|
||||
|
||||
private void initSetting(File setting) {
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "Thanks for using Mirai");
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "initializing Settings");
|
||||
getLogger().info("Thanks for using Mirai");
|
||||
getLogger().info("initializing Settings");
|
||||
try {
|
||||
if(setting.createNewFile()){
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "Mirai Config Created");
|
||||
if (setting.createNewFile()) {
|
||||
getLogger().info("Mirai Config Created");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.setting = new MiraiSetting(setting);
|
||||
MiraiSettingMapSection network = this.setting.getMapSection("network");
|
||||
network.set("enable_proxy","not supporting yet");
|
||||
MiraiSettingMapSection network = this.setting.getMapSection("network");
|
||||
network.set("enable_proxy", "not supporting yet");
|
||||
|
||||
MiraiSettingListSection proxy = this.setting.getListSection("proxy");
|
||||
MiraiSettingListSection proxy = this.setting.getListSection("proxy");
|
||||
proxy.add("1.2.3.4:95");
|
||||
proxy.add("1.2.3.4:100");
|
||||
|
||||
MiraiSettingMapSection worker = this.setting.getMapSection("worker");
|
||||
worker.set("core_task_pool_worker_amount",5);
|
||||
MiraiSettingMapSection worker = this.setting.getMapSection("worker");
|
||||
worker.set("core_task_pool_worker_amount", 5);
|
||||
|
||||
MiraiSettingMapSection plugin = this.setting.getMapSection("plugin");
|
||||
plugin.set("debug", false);
|
||||
|
||||
this.setting.save();
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "initialized; changing can be made in setting file: " + setting.toString());
|
||||
getLogger().info("initialized; changing can be made in setting file: " + setting.toString());
|
||||
}
|
||||
|
||||
private void initQQConfig(File qqConfig){
|
||||
private void initQQConfig(File qqConfig) {
|
||||
this.qqs = new MiraiConfig(qqConfig);
|
||||
|
||||
MiraiConfigSection<Object> section = new MiraiConfigSection<>();
|
||||
|
||||
System.out.println("/");
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "input one " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.SKY_BLUE + "for default robotNetworkHandler");
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "输入用于默认机器人的QQ号");
|
||||
getLogger().info("Input a " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.GREEN + "for default robotNetworkHandler");
|
||||
getLogger().info("输入用于默认机器人的QQ号");
|
||||
long qqNumber = scanner.nextLong();
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "input the password for that QQ account");
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "输入该QQ号对应密码");
|
||||
getLogger().info("Input the password for that QQ account");
|
||||
getLogger().info("输入该QQ号的密码");
|
||||
String qqPassword = scanner.next();
|
||||
|
||||
section.put("password",qqPassword);
|
||||
section.put("owner","default");
|
||||
section.put("password", qqPassword);
|
||||
section.put("owner", "default");
|
||||
|
||||
this.qqs.put(String.valueOf(qqNumber),section);
|
||||
this.qqs.put(String.valueOf(qqNumber), section);
|
||||
this.qqs.save();
|
||||
getLogger().info(LoggerTextFormat.SKY_BLUE + "QQ account initialized; changing can be made in Config file: " + qqConfig.toString());
|
||||
getLogger().info("QQ account initialized; changing can be made in Config file: " + qqConfig.toString());
|
||||
}
|
||||
|
||||
private void onEnable(){
|
||||
private void onEnable() {
|
||||
this.eventManager.broadcastEvent(new ServerEnableEvent());
|
||||
this.enabled = true;
|
||||
getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai");
|
||||
|
@ -1,7 +1,10 @@
|
||||
package net.mamoe.mirai;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.mamoe.mirai.contact.Group;
|
||||
import net.mamoe.mirai.contact.QQ;
|
||||
import net.mamoe.mirai.network.RobotNetworkHandler;
|
||||
import net.mamoe.mirai.utils.ContactList;
|
||||
import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -10,10 +13,8 @@ import java.util.List;
|
||||
|
||||
public class Robot {
|
||||
|
||||
private final int qq;
|
||||
private final int qqNumber;
|
||||
private final String password;
|
||||
|
||||
|
||||
@Getter
|
||||
private final RobotNetworkHandler handler;
|
||||
|
||||
@ -23,6 +24,9 @@ public class Robot {
|
||||
@Getter
|
||||
private final List<String> owners;
|
||||
|
||||
private final ContactList<Group> groups = new ContactList<>();
|
||||
private final ContactList<QQ> qqs = new ContactList<>();
|
||||
|
||||
public boolean isOwnBy(String ownerName) {
|
||||
return owners.contains(ownerName);
|
||||
}
|
||||
@ -30,20 +34,36 @@ public class Robot {
|
||||
|
||||
public Robot(MiraiConfigSection<Object> data) throws Throwable {
|
||||
this(
|
||||
data.getIntOrThrow("account", () -> new Exception("can not parse QQ account")),
|
||||
data.getStringOrThrow("password", () -> new Exception("can not parse QQ password")),
|
||||
data.getIntOrThrow("account", () -> new IllegalArgumentException("account")),
|
||||
data.getStringOrThrow("password", () -> new IllegalArgumentException("password")),
|
||||
data.getAsOrDefault("owners", ArrayList::new)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Robot(int qq, String password, List<String> owners) {
|
||||
this.qq = qq;
|
||||
public Robot(int qqNumber, String password, List<String> owners) {
|
||||
this.qqNumber = qqNumber;
|
||||
this.password = password;
|
||||
this.owners = Collections.unmodifiableList(owners);
|
||||
this.handler = new RobotNetworkHandler(this, this.qq, this.password);
|
||||
this.handler = new RobotNetworkHandler(this, this.qqNumber, this.password);
|
||||
}
|
||||
|
||||
public QQ getQQ(int qqNumber) {
|
||||
if (!this.qqs.containsKey(qqNumber)) {
|
||||
this.qqs.put(qqNumber, new QQ(qqNumber));
|
||||
}
|
||||
return this.qqs.get(qqNumber);
|
||||
}
|
||||
|
||||
public Group getGroup(int groupNumber) {
|
||||
if (!this.groups.containsKey(groupNumber)) {
|
||||
this.groups.put(groupNumber, new Group(groupNumber));
|
||||
}
|
||||
return groups.get(groupNumber);
|
||||
}
|
||||
|
||||
public Group getGroupByGroupId(int groupId) {
|
||||
return getGroup(Group.Companion.groupIdToNumber(groupId));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
import net.mamoe.mirai.message.Message
|
||||
import net.mamoe.mirai.utils.ContactList
|
||||
|
||||
class Group(number: Int) : Contact(number) {
|
||||
val groupId = groupNumberToId(number)
|
||||
val members = ContactList<QQ>()
|
||||
|
||||
init {
|
||||
Instances.groups.add(this)
|
||||
@ -55,6 +57,11 @@ class Group(number: Int) : Contact(number) {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
groupNumberToId(580266363)
|
||||
}
|
||||
|
||||
fun groupIdToNumber(id: Int): Int {
|
||||
var left: Int = id.toString().let {
|
||||
if (it.length < 6) {
|
||||
|
@ -0,0 +1,23 @@
|
||||
package net.mamoe.mirai.event.events.group;
|
||||
|
||||
import net.mamoe.mirai.Robot;
|
||||
import net.mamoe.mirai.contact.Group;
|
||||
import net.mamoe.mirai.event.events.robot.RobotEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public abstract class GroupEvent extends RobotEvent {
|
||||
private final Group group;
|
||||
|
||||
public GroupEvent(Robot robot, Group group) {
|
||||
super(robot);
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Group getGroup() {
|
||||
return group;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package net.mamoe.mirai.event.events.group;
|
||||
|
||||
import net.mamoe.mirai.Robot;
|
||||
import net.mamoe.mirai.contact.Group;
|
||||
import net.mamoe.mirai.contact.QQ;
|
||||
import net.mamoe.mirai.message.defaults.MessageChain;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public final class GroupMessageEvent extends GroupEvent {
|
||||
private final QQ sender;
|
||||
private final MessageChain messageChain;
|
||||
private final String messageString;
|
||||
|
||||
public GroupMessageEvent(@NotNull Robot robot, @NotNull Group group, @NotNull QQ sender, @NotNull MessageChain messageChain) {
|
||||
super(robot, group);
|
||||
this.sender = sender;
|
||||
this.messageChain = messageChain;
|
||||
this.messageString = messageChain.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MessageChain getMessageChain() {
|
||||
return messageChain;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMessageString() {
|
||||
return messageString;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public QQ getSender() {
|
||||
return sender;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package net.mamoe.mirai.event.events.qq;
|
||||
|
||||
import net.mamoe.mirai.Robot;
|
||||
import net.mamoe.mirai.contact.QQ;
|
||||
import net.mamoe.mirai.event.events.robot.RobotEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public abstract class FriendEvent extends RobotEvent {
|
||||
private final QQ qq;
|
||||
|
||||
public FriendEvent(@NotNull Robot robot, @NotNull QQ qq) {
|
||||
super(robot);
|
||||
this.qq = Objects.requireNonNull(qq);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public QQ getQQ() {
|
||||
return qq;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package net.mamoe.mirai.event.events.qq;
|
||||
|
||||
import net.mamoe.mirai.Robot;
|
||||
import net.mamoe.mirai.contact.QQ;
|
||||
import net.mamoe.mirai.message.defaults.MessageChain;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public final class FriendMessageEvent extends FriendEvent {
|
||||
private final MessageChain messageChain;
|
||||
private final String messageString;
|
||||
|
||||
public FriendMessageEvent(@NotNull Robot robot, @NotNull QQ sender, @NotNull MessageChain messageChain) {
|
||||
super(robot, sender);
|
||||
this.messageChain = Objects.requireNonNull(messageChain);
|
||||
this.messageString = messageChain.toString();
|
||||
}
|
||||
|
||||
public String getMessageString() {
|
||||
return messageString;
|
||||
}
|
||||
|
||||
public MessageChain getMessageChain() {
|
||||
return messageChain;
|
||||
}
|
||||
}
|
@ -2,15 +2,20 @@ package net.mamoe.mirai.event.events.robot;
|
||||
|
||||
import net.mamoe.mirai.Robot;
|
||||
import net.mamoe.mirai.event.events.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;
|
||||
}
|
||||
|
||||
public RobotEvent(Robot robot){
|
||||
this.robot = robot;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package net.mamoe.mirai.event.events.server;
|
||||
|
||||
import net.mamoe.mirai.event.events.MiraiEvent;
|
||||
|
||||
public class ServerDisableEvent extends MiraiEvent {
|
||||
public final class ServerDisableEvent extends MiraiEvent {
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package net.mamoe.mirai.event.events.server;
|
||||
|
||||
import net.mamoe.mirai.event.events.MiraiEvent;
|
||||
|
||||
public class ServerEnableEvent extends MiraiEvent {
|
||||
public final class ServerEnableEvent extends MiraiEvent {
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,9 +3,12 @@ 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
|
||||
@ -21,6 +24,19 @@ public final class MessageChain extends Message {
|
||||
list.add(tail);
|
||||
}
|
||||
|
||||
public MessageChain(@NotNull Message message) {
|
||||
Objects.requireNonNull(message);
|
||||
list.add(message);
|
||||
}
|
||||
|
||||
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(""));
|
||||
|
@ -2,11 +2,14 @@ package net.mamoe.mirai.network
|
||||
|
||||
import net.mamoe.mirai.MiraiServer
|
||||
import net.mamoe.mirai.Robot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.event.events.qq.FriendMessageEvent
|
||||
import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent
|
||||
import net.mamoe.mirai.network.packet.*
|
||||
import net.mamoe.mirai.network.packet.login.*
|
||||
import net.mamoe.mirai.network.packet.message.ClientSendFriendMessagePacket
|
||||
import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket
|
||||
import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
|
||||
import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
|
||||
import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacket
|
||||
import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted
|
||||
import net.mamoe.mirai.task.MiraiThreadPool
|
||||
@ -84,6 +87,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
*/
|
||||
private lateinit var cookies: String
|
||||
private var gtk: Int = 0
|
||||
private var ignoreMessage: Boolean = false
|
||||
|
||||
init {
|
||||
tlv0105 = lazyEncode {
|
||||
@ -197,6 +201,11 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
sendPacket(ClientHeartbeatPacket(this.number, this.sessionKey))
|
||||
}, 90000, 90000, TimeUnit.MILLISECONDS)
|
||||
RobotLoginSucceedEvent(robot).broadcast()
|
||||
|
||||
MiraiThreadPool.getInstance().schedule({
|
||||
ignoreMessage = false
|
||||
}, 2, TimeUnit.SECONDS)
|
||||
|
||||
this.tlv0105 = packet.tlv0105
|
||||
sendPacket(ClientLoginStatusPacket(this.number, this.sessionKey, ClientLoginStatus.ONLINE))
|
||||
}
|
||||
@ -225,23 +234,23 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
|
||||
}
|
||||
|
||||
is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
|
||||
|
||||
|
||||
is ServerFriendMessageEventPacket -> {
|
||||
println(packet.toString())
|
||||
if (packet.message == "牛逼") {
|
||||
sendPacket(ClientSendFriendMessagePacket(this.number, packet.qq, this.sessionKey, "牛逼!!"))
|
||||
if (ignoreMessage) {
|
||||
return
|
||||
}
|
||||
|
||||
//friend message
|
||||
FriendMessageEvent(this.robot, this.robot.getQQ(packet.qq), packet.message)
|
||||
}
|
||||
|
||||
is ServerGroupMessageEventPacket -> {
|
||||
//group message
|
||||
if (packet.message == "牛逼") {
|
||||
sendPacket(ClientSendGroupMessagePacket(packet.group, this.number, this.sessionKey, "牛逼!"))
|
||||
sendPacket(ClientSendGroupMessagePacket(Group.groupNumberToId(packet.groupNumber), this.number, this.sessionKey, "牛逼!"))
|
||||
}
|
||||
|
||||
//todo
|
||||
//GroupMessageEvent(this.robot, this.robot.getGroup(packet.groupNumber), this.robot.getQQ(packet.qq), packet.message)
|
||||
}
|
||||
|
||||
is UnknownServerEventPacket -> {
|
||||
@ -256,6 +265,8 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
|
||||
}
|
||||
|
||||
is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
|
||||
|
||||
is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt(this.token00BA))
|
||||
is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
|
||||
is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
|
||||
@ -267,6 +278,11 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
is ServerMessageEventPacketRawEncoded -> onPacketReceived(packet.decrypt(this.sessionKey))
|
||||
|
||||
|
||||
is ServerSendFriendMessageResponsePacket,
|
||||
is ServerSendGroupMessageResponsePacket -> {
|
||||
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException(packet.toString())
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.mamoe.mirai.network.packet
|
||||
|
||||
import net.mamoe.mirai.message.defaults.MessageChain
|
||||
import net.mamoe.mirai.message.defaults.PlainText
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.DataInputStream
|
||||
@ -29,15 +31,15 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra
|
||||
* 群文件上传
|
||||
*/
|
||||
class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
lateinit var message: String
|
||||
lateinit var xmlMessage: String
|
||||
|
||||
override fun decode() {
|
||||
message = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
|
||||
xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
|
||||
}//todo test
|
||||
}
|
||||
|
||||
class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
var group: Int = 0
|
||||
var groupNumber: Int = 0
|
||||
var qq: Int = 0
|
||||
lateinit var message: String
|
||||
lateinit var messageType: MessageType
|
||||
@ -57,10 +59,10 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
||||
}
|
||||
|
||||
override fun decode() {
|
||||
group = this.input.goto(51).readInt()
|
||||
groupNumber = this.input.goto(51).readInt()
|
||||
qq = this.input.goto(56).readInt()
|
||||
val fontLength = this.input.goto(108).readShort()
|
||||
//println(this.input.goto(110 + fontLength).readNBytes(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()) {
|
||||
19 -> MessageType.NORMAL
|
||||
@ -102,7 +104,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
||||
message = "[face${faceId}.gif]"
|
||||
}
|
||||
|
||||
MessageType.AT, MessageType.OTHER -> {
|
||||
MessageType.AT, MessageType.OTHER, MessageType.PLAIN_TEXT, MessageType.IMAGE, MessageType.ANONYMOUS -> {
|
||||
var messageLength: Int = this.input.goto(110 + fontLength + 6).readShort().toInt()
|
||||
message = String(this.input.goto(110 + fontLength + 8).readNBytes(messageLength))
|
||||
|
||||
@ -120,7 +122,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
||||
|
||||
//读取 nick, ignore.
|
||||
/*
|
||||
when (this.input.goto(110 + fontLength + 3 + oeLength).readByte().toInt()) {
|
||||
when (this.input.goto(110 + fontLength + 3 + oeLength).readByteAt().toInt()) {
|
||||
12 -> {
|
||||
this.input.skip(4)//maybe 5?
|
||||
|
||||
@ -139,6 +141,35 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
||||
}
|
||||
}
|
||||
|
||||
class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
var qq: Int = 0
|
||||
lateinit var message: MessageChain
|
||||
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
//start at Sep1.0:27
|
||||
input.goto(0)
|
||||
println(input.readAllBytes().toUHexString())
|
||||
input.goto(0)
|
||||
|
||||
qq = input.readIntAt(0)
|
||||
val msgLength = input.readShortAt(22)
|
||||
val fontLength = input.readShortAt(93 + msgLength)
|
||||
val offset = msgLength + fontLength
|
||||
message = MessageChain(PlainText(let {
|
||||
val offset2 = input.readShortAt(101 + offset)
|
||||
input.goto(103 + offset).readVarString(offset2.toInt())
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
backup
|
||||
|
||||
class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
var qq: Int = 0
|
||||
lateinit var message: String
|
||||
@ -147,17 +178,17 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
//start at Sep1.0:27
|
||||
qq = input.readInt(0)
|
||||
val msgLength = input.readShort(22)
|
||||
val fontLength = input.readShort(93+msgLength)
|
||||
qq = input.readIntAt(0)
|
||||
val msgLength = input.readShortAt(22)
|
||||
val fontLength = input.readShortAt(93+msgLength)
|
||||
val offset = msgLength+fontLength
|
||||
message = if(input.readByte(97+offset).toUHexString() == "02"){
|
||||
"[face" + input.goto(103+offset).readByte(1).toInt().toString() + ".gif]"
|
||||
message = if(input.readByteAt(97+offset).toUHexString() == "02"){
|
||||
"[face" + input.goto(103+offset).readByteAt(1).toInt().toString() + ".gif]"
|
||||
//.gif
|
||||
}else {
|
||||
val offset2 = input.readShort(101 + offset)
|
||||
val offset2 = input.readShortAt(101 + offset)
|
||||
input.goto(103 + offset).readVarString(offset2.toInt())
|
||||
}
|
||||
// TODO("FRIEND 解析")d
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
@ -145,22 +145,22 @@ infix fun <N : Number> DataInputStream.goto(position: N): DataInputStream {
|
||||
return this
|
||||
}
|
||||
|
||||
fun <N : Number> DataInputStream.readNBytes(position: N, length: Int): ByteArray {
|
||||
fun <N : Number> DataInputStream.readNBytesAt(position: N, length: Int): ByteArray {
|
||||
this.goto(position)
|
||||
return this.readNBytes(length)
|
||||
}
|
||||
|
||||
fun <N : Number> DataInputStream.readInt(position: N): Int {
|
||||
fun <N : Number> DataInputStream.readIntAt(position: N): Int {
|
||||
this.goto(position)
|
||||
return this.readInt();
|
||||
}
|
||||
|
||||
fun <N : Number> DataInputStream.readByte(position: N): Byte {
|
||||
fun <N : Number> DataInputStream.readByteAt(position: N): Byte {
|
||||
this.goto(position)
|
||||
return this.readByte();
|
||||
}
|
||||
|
||||
fun <N : Number> DataInputStream.readShort(position: N): Short {
|
||||
fun <N : Number> DataInputStream.readShortAt(position: N): Short {
|
||||
this.goto(position)
|
||||
return this.readShort();
|
||||
}
|
@ -3,7 +3,7 @@ package net.mamoe.mirai.network.packet.login
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.network.packet.ServerPacket
|
||||
import net.mamoe.mirai.network.packet.goto
|
||||
import net.mamoe.mirai.network.packet.readNBytes
|
||||
import net.mamoe.mirai.network.packet.readNBytesAt
|
||||
import net.mamoe.mirai.network.packet.readVarString
|
||||
import net.mamoe.mirai.util.TestedSuccessfully
|
||||
import net.mamoe.mirai.utils.TEACryptor
|
||||
@ -31,16 +31,16 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
|
||||
* Version 1 @Deprecated
|
||||
this.input.skip(7)//8
|
||||
|
||||
encryptionKey = this.input.readNBytes(16)//24
|
||||
encryptionKey = this.input.readNBytesAt(16)//24
|
||||
|
||||
this.input.skip(2)//25->26
|
||||
|
||||
token38 = this.input.readNBytes(56)//81->82
|
||||
token38 = this.input.readNBytesAt(56)//81->82
|
||||
|
||||
this.input.skip(60L)//142
|
||||
|
||||
//??
|
||||
var b = this.input.readNBytes(2)
|
||||
var b = this.input.readNBytesAt(2)
|
||||
val msgLength = when (b.toUByteArray().toUHexString()) {
|
||||
"01 07" -> 0
|
||||
"00 33" -> 28
|
||||
@ -55,17 +55,17 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
|
||||
|
||||
this.input.skip(10)//171+msgLength
|
||||
|
||||
_0828_rec_decr_key = this.input.readNBytes(16)//187+msgLength
|
||||
_0828_rec_decr_key = this.input.readNBytesAt(16)//187+msgLength
|
||||
|
||||
|
||||
this.input.skip(2)
|
||||
|
||||
token88 = this.input.readNBytes(136)//325+ // msgLength
|
||||
token88 = this.input.readNBytesAt(136)//325+ // msgLength
|
||||
|
||||
this.input.skip(299L)//624+msgLength
|
||||
|
||||
//varString (nickLength bytes)
|
||||
val nickLength = this.input.readByte().toInt()//625+msgLength
|
||||
val nickLength = this.input.readByteAt().toInt()//625+msgLength
|
||||
|
||||
System.out.println(nickLength)
|
||||
|
||||
@ -76,11 +76,11 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
|
||||
/*
|
||||
this.input.skip((dataIndex - (625 + msgLength + nickLength)) + 0L)//-31
|
||||
|
||||
gender = this.input.readByte().toUByte().toInt()//-30
|
||||
gender = this.input.readByteAt().toUByte().toInt()//-30
|
||||
|
||||
this.input.skip(9)//-27
|
||||
|
||||
age = this.input.readShort()//-25
|
||||
age = this.input.readShortAt()//-25
|
||||
*/
|
||||
age = 0
|
||||
gender = 0
|
||||
@ -106,16 +106,16 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
|
||||
else -> throw IllegalStateException(id)
|
||||
}
|
||||
|
||||
this._0828_rec_decr_key = this.input.readNBytes(171 + msgLength, 16)
|
||||
this._0828_rec_decr_key = this.input.readNBytesAt(171 + msgLength, 16)
|
||||
|
||||
this.token88 = this.input.readNBytes(189 + msgLength, 136)
|
||||
this.token88 = this.input.readNBytesAt(189 + msgLength, 136)
|
||||
|
||||
val nickLength = this.input.goto(624 + msgLength).readByte().toInt()
|
||||
this.nick = this.input.readVarString(nickLength)
|
||||
|
||||
//this.age = this.input.goto(packetDataLength - 28).readShort()
|
||||
//this.age = this.input.goto(packetDataLength - 28).readShortAt()
|
||||
|
||||
//this.gender = this.input.goto(packetDataLength - 32).readByte().toInt()
|
||||
//this.gender = this.input.goto(packetDataLength - 32).readByteAt().toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ package net.mamoe.mirai.network.packet.message
|
||||
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.network.packet.*
|
||||
import net.mamoe.mirai.utils.lazyEncode
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
@ -21,6 +23,11 @@ class ClientSendGroupMessagePacket(
|
||||
this.writeHex(Protocol._fixVer)
|
||||
|
||||
this.encryptAndWrite(sessionKey) {
|
||||
val bytes = message.toByteArray()
|
||||
it.writeByte(0x2A)
|
||||
it.writeInt(groupId)
|
||||
it.writeShort(56 + bytes.size)
|
||||
|
||||
it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00")
|
||||
it.writeTime()
|
||||
it.writeRandom(4)
|
||||
@ -28,21 +35,33 @@ class ClientSendGroupMessagePacket(
|
||||
it.writeZero(2)
|
||||
|
||||
//messages
|
||||
val bytes = message.toByteArray()
|
||||
it.writeByte(0x2A)
|
||||
it.writeInt(groupId)
|
||||
it.writeShort(19 + bytes.size)
|
||||
|
||||
it.writeByte(0x01)
|
||||
it.writeByte(0x01)
|
||||
it.writeShort(bytes.size + 3)
|
||||
it.writeByte(0x01)
|
||||
it.writeShort(bytes.size)
|
||||
it.write(bytes)
|
||||
|
||||
println(it.toByteArray().toUHexString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
println(lazyEncode {
|
||||
val bytes = "message".toByteArray()
|
||||
it.writeByte(0x2A)
|
||||
it.writeInt(580266363)
|
||||
it.writeShort(19 + bytes.size)
|
||||
|
||||
it.writeByte(0x01)
|
||||
it.writeByte(0x01)
|
||||
it.writeShort(bytes.size + 3)
|
||||
it.writeByte(0x01)
|
||||
it.writeShort(bytes.size)
|
||||
it.write(bytes)
|
||||
}.toUHexString())
|
||||
}
|
||||
|
||||
@PacketId("00 02")
|
||||
class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) {
|
||||
override fun decode() {
|
||||
|
@ -27,7 +27,7 @@ class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input)
|
||||
|
||||
this.unknownBoolean = this.input.readByte().toInt() == 1
|
||||
|
||||
//this.token00BA = this.input.goto(packetLength - 60).readNBytes(40)
|
||||
//this.token00BA = this.input.goto(packetLength - 60).readNBytesAt(40)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
package net.mamoe.mirai.utils;
|
||||
|
||||
import net.mamoe.mirai.contact.Contact;
|
||||
import net.mamoe.mirai.utils.config.MiraiSynchronizedLinkedListMap;
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public class ContactList<C extends Contact> extends MiraiSynchronizedLinkedListMap<Integer, C> {
|
||||
}
|
@ -1,14 +1,25 @@
|
||||
package net.mamoe.mirai.utils;
|
||||
|
||||
import net.mamoe.mirai.MiraiServer;
|
||||
|
||||
public enum LoggerTextFormat {
|
||||
RED("\033[31m"),
|
||||
GREEN("\033[32m"),
|
||||
YELLOW("\033[33m"),
|
||||
BLUE("\033[34m"),
|
||||
SKY_BLUE("\033[36m"),
|
||||
RESET("\33[0m");
|
||||
RESET("\33[0m"),
|
||||
|
||||
BLUE("\033[0;34m"),
|
||||
BLACK("\033[0;30m"),
|
||||
DARK_GREY("\033[1;30m"),
|
||||
LIGHT_BLUE("\033[1;34m"),
|
||||
GREEN("\033[0;32m"),
|
||||
LIGHT_GTEEN("\033[1;32m"),
|
||||
CYAN("\033[0;36m"),
|
||||
LIGHT_CYAN("\033[1;36m"),
|
||||
RED("\033[0;31m"),
|
||||
LIGHT_RED("\033[1;31m"),
|
||||
PURPLE("\033[0;35m"),
|
||||
LIGHT_PURPLE("\033[1;35m"),
|
||||
BROWN("\033[0;33m"),
|
||||
YELLOW("\033[1;33m"),
|
||||
LIGHT_GRAY("\033[0;37m"),
|
||||
WHITE("\033[1;37m");
|
||||
|
||||
private String format;
|
||||
|
||||
LoggerTextFormat(String format) {
|
||||
@ -17,9 +28,9 @@ public enum LoggerTextFormat {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if(MiraiServer.getInstance().isUnix()){
|
||||
return format;
|
||||
}
|
||||
return "";
|
||||
//if(MiraiServer.getInstance().isUnix()){
|
||||
return format;
|
||||
// }
|
||||
// return "";
|
||||
}
|
||||
}
|
||||
|
@ -7,21 +7,16 @@ import java.util.*
|
||||
* used to replace old logger
|
||||
*/
|
||||
object MiraiLogger {
|
||||
infix fun info(o: Any?) {
|
||||
this.print(o.toString())
|
||||
}
|
||||
|
||||
infix fun error(o: Any?) {
|
||||
this.print(o.toString(), LoggerTextFormat.RED)
|
||||
}
|
||||
|
||||
infix fun log(o: Any?) = info(o)
|
||||
|
||||
infix fun println(o: Any?) = info(o)
|
||||
infix fun info(o: Any?) = this.print(o.toString(), LoggerTextFormat.RESET)
|
||||
|
||||
infix fun debug(o: Any?) {
|
||||
this.print(o.toString())
|
||||
}
|
||||
|
||||
infix fun error(o: Any?) = this.print(o.toString(), LoggerTextFormat.RED)
|
||||
|
||||
infix fun notice(o: Any?) = this.print(o.toString(), LoggerTextFormat.LIGHT_BLUE)
|
||||
|
||||
infix fun debug(o: Any?) = this.print(o.toString(), LoggerTextFormat.YELLOW)
|
||||
|
||||
infix fun catching(e: Throwable) {
|
||||
e.printStackTrace()
|
||||
@ -31,7 +26,7 @@ object MiraiLogger {
|
||||
this.print(e.cause.toString())*/
|
||||
}
|
||||
|
||||
private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.BLUE) {
|
||||
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")
|
||||
}
|
||||
@ -42,4 +37,6 @@ fun Any.logInfo() = MiraiLogger.info(this)
|
||||
|
||||
fun Any.logDebug() = MiraiLogger.debug(this)
|
||||
|
||||
fun Any.logError() = MiraiLogger.error(this)
|
||||
fun Any.logError() = MiraiLogger.error(this)
|
||||
|
||||
fun Any.logNotice() = MiraiLogger.notice(this)
|
@ -6,12 +6,10 @@ import net.mamoe.mirai.network.Protocol;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
@ -213,16 +211,16 @@ public class HexComparator {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
/*
|
||||
|
||||
System.out.println(HexComparator.compare(
|
||||
//mirai
|
||||
|
||||
"01 12 00 38 56 3A E4 8B B4 64 D2 72 60 FE 01 54 FC B1 5F 88 E0 BA 64 1A 55 F2 84 FC 97 D0 BF 5F 47 A8 D9 76 BB FB 4A 7A F3 5E 0E A4 8E CA 8F 27 C2 02 6E 5D E7 68 9F 7C CF 91 83 F4 03 0F 00 11 00 0F 44 45 53 4B 54 4F 50 2D 4D 31 37 4A 52 45 55 00 05 00 06 00 02 76 E4 B8 DD 00 06 00 78 0D DF 92 9C 5A 08 D1 67 FD 7D D6 DE CE D0 92 39 79 17 53 57 41 9B D6 D3 F9 F8 9A 3B E1 C2 3A E7 CF 02 6E 5E 36 B7 6D CF 33 66 77 FE AC 58 93 A3 85 E7 AF 6F 2D A2 74 E2 60 28 4B 29 17 04 79 95 39 D4 BF 4D C1 ED 61 49 13 23 9D 71 62 29 AF 87 D7 E3 42 49 88 3F D8 5C DB 9F 9E 5A 2A EA 02 F6 4F 2B D3 5B AF BE 0C B2 54 46 AE 99 1B 07 0B BE 6A C2 29 18 25 6A 95 0A 00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B 00 1A 00 40 E2 9A D0 B3 7D CD 3D F4 55 DB 04 A4 68 2A AF 4E 38 46 8B E0 1F 2D 2A B8 F6 C6 AB 4F DF D1 5F 8C D4 CA 2A 91 25 14 33 A3 C5 08 F8 01 4C E6 3D 89 5F 23 38 3A EC 01 58 F6 B1 F6 7F 2E 6A 02 17 4A 00 18 00 16 00 01 00 00 04 53 00 00 00 01 00 00 15 85 76 E4 B8 DD 00 00 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6 01 10 00 3C 00 01 00 38 57 3A 37 C3 FB A0 C3 E5 AE F3 0E B6 03 DE BF 9E E2 B5 C5 FE A0 F0 03 4F F7 8A 5C 29 5C E0 5A A2 89 D5 3F 60 E2 B2 81 FE D4 16 04 D4 E3 C6 4A D7 A9 D9 E6 FC 2E 7E 0C F3 03 12 00 05 01 00 00 00 01 05 08 00 05 10 00 00 00 00 03 13 00 19 01 01 02 00 10 04 EA 78 D1 A4 FF CD CC 7C B8 D4 12 7D BB 03 AA 00 00 00 00 01 02 00 62 00 01 04 EB B7 C1 86 F9 08 96 ED 56 84 AB 50 85 2E 48 00 38 E9 AA 2B 4D 26 4C 76 18 FE 59 D5 A9 82 6A 0C 04 B4 49 50 D7 9B B1 FE 5D 97 54 8D 82 F3 22 C2 48 B9 C9 22 69 CA 78 AD 3E 2D E9 C9 DF A8 9E 7D 8C 8D 6B DF 4C D7 34 D0 D3 00 14 10 21 DF C4 F3 DD 42 09 6F A0 93 8C 7E 0E 78 EF 22 8D 88 35"
|
||||
"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"
|
||||
,
|
||||
//e
|
||||
"01 12 00 38 56 3A E4 8B B4 64 D2 72 60 FE 01 54 FC B1 5F 88 E0 BA 64 1A 55 F2 84 FC 97 D0 BF 5F 47 A8 D9 76 BB FB 4A 7A F3 5E 0E A4 8E CA 8F 27 C2 02 6E 5D E7 68 9F 7C CF 91 83 F4 03 0F 00 11 00 0F 44 45 53 4B 54 4F 50 2D 4D 31 37 4A 52 45 55 00 05 00 06 00 02 76 E4 B8 DD 00 06 00 78 0D DF 92 9C 5A 08 D1 67 FD 7D D6 DE CE D0 92 39 79 17 53 57 41 9B D6 D3 F9 F8 9A 3B E1 C2 3A E7 CF 02 6E 5E 36 B7 6D CF 33 66 77 FE AC 58 93 A3 85 E7 AF 6F 2D A2 74 E2 60 28 4B 29 17 04 79 95 39 D4 BF 4D C1 ED 61 49 13 23 9D 71 62 29 AF 87 D7 E3 42 49 88 3F D8 5C DB 9F 9E 5A 2A EA 02 F6 4F 2B D3 5B AF BE 0C B2 54 46 AE 99 1B 07 0B BE 6A C2 29 18 25 6A 95 0A 00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B 00 1A 00 40 26 2B FE EB 21 8E 08 16 BA 42 B3 A3 C5 6A 5B 31 33 A9 B3 F0 EB 16 80 BE F0 58 D3 51 98 2F A7 23 27 7C 06 97 F4 85 01 77 5C 5B D6 A2 82 54 06 A0 07 53 39 E2 E7 62 E5 09 1A 25 79 6F D9 E0 ED B6 00 18 00 16 00 01 00 00 04 53 00 00 00 01 00 00 15 85 76 E4 B8 DD 00 00 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6 01 10 00 3C 00 01 00 38 57 3A 37 C3 FB A0 C3 E5 AE F3 0E B6 03 DE BF 9E E2 B5 C5 FE A0 F0 03 4F F7 8A 5C 29 5C E0 5A A2 89 D5 3F 60 E2 B2 81 FE D4 16 04 D4 E3 C6 4A D7 A9 D9 E6 FC 2E 7E 0C F3 03 12 00 05 01 00 00 00 01 05 08 00 05 01 00 00 00 00 03 13 00 19 01 01 02 00 10 04 EA 78 D1 A4 FF CD CC 7C B8 D4 12 7D BB 03 AA 00 00 00 00 01 02 00 62 00 01 04 EB B7 C1 86 F9 08 96 ED 56 84 AB 50 85 2E 48 00 38 E9 AA 2B 4D 26 4C 76 18 FE 59 D5 A9 82 6A 0C 04 B4 49 50 D7 9B B1 FE 5D 97 54 8D 82 F3 22 C2 48 B9 C9 22 69 CA 78 AD 3E 2D E9 C9 DF A8 9E 7D 8C 8D 6B DF 4C D7 34 D0 D3 00 14 4C 97 73 32 83 1A 6F C4 94 91 0A 7A D8 21 81 58 73 3D 24 F6"
|
||||
"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"
|
||||
));
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
System.out.println(HexComparator.compare(
|
||||
|
Loading…
Reference in New Issue
Block a user