Commit 4ce8fe60 authored by Him188moe's avatar Him188moe

update

parent fa4adfd5
...@@ -25,6 +25,18 @@ ...@@ -25,6 +25,18 @@
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-all</artifactId> <artifactId>netty-all</artifactId>
</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>
</dependencies> </dependencies>
<build> <build>
......
package net.mamoe.mirai; package net.mamoe.mirai;
import lombok.Getter; import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import net.mamoe.mirai.event.MiraiEventManager; import net.mamoe.mirai.event.MiraiEventManager;
import net.mamoe.mirai.event.events.server.ServerDisableEvent; import net.mamoe.mirai.event.events.server.ServerDisableEvent;
import net.mamoe.mirai.event.events.server.ServerEnableEvent; import net.mamoe.mirai.event.events.server.ServerEnableEvent;
...@@ -9,20 +10,18 @@ import net.mamoe.mirai.network.MiraiUDPClient; ...@@ -9,20 +10,18 @@ import net.mamoe.mirai.network.MiraiUDPClient;
import net.mamoe.mirai.network.MiraiUDPServer; import net.mamoe.mirai.network.MiraiUDPServer;
import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.task.MiraiTaskManager;
import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.LoggerTextFormat;
import net.mamoe.mirai.utils.MiraiLogger;
import net.mamoe.mirai.utils.config.MiraiConfig; import net.mamoe.mirai.utils.config.MiraiConfig;
import net.mamoe.mirai.utils.config.MiraiMapSection; import net.mamoe.mirai.utils.config.MiraiMapSection;
import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.InetAddress; import java.net.InetAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Scanner; import java.util.Scanner;
@Log4j2
public class MiraiServer { public class MiraiServer {
@Getter @Getter
private static MiraiServer instance; private static MiraiServer instance;
...@@ -44,11 +43,12 @@ public class MiraiServer { ...@@ -44,11 +43,12 @@ public class MiraiServer {
MiraiEventManager eventManager; MiraiEventManager eventManager;
@Getter @Getter
MiraiTaskManager taskManager; MiraiTaskManager taskManager;
@Getter
MiraiLogger logger;
MiraiConfig setting; MiraiConfig setting;
public static Logger getLogger() {
return log;
}
protected MiraiServer(){ protected MiraiServer(){
instance = this; instance = this;
...@@ -60,25 +60,22 @@ public class MiraiServer { ...@@ -60,25 +60,22 @@ public class MiraiServer {
protected void shutdown(){ protected void shutdown(){
if(this.enabled) { if(this.enabled) {
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "About to shutdown Mirai"); getLogger().info(LoggerTextFormat.SKY_BLUE + "About to shutdown Mirai");
this.getEventManager().boardcastEvent(new ServerDisableEvent()); this.getEventManager().boardcastEvent(new ServerDisableEvent());
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "Data have been saved"); getLogger().info(LoggerTextFormat.SKY_BLUE + "Data have been saved");
} }
} }
private void onLoad(){ private void onLoad(){
this.parentFolder = new File(System.getProperty("user.dir")); this.parentFolder = new File(System.getProperty("user.dir"));
this.unix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS"); this.unix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS");
this.logger = MiraiLogger.getInstance();
this.eventManager = MiraiEventManager.getInstance(); this.eventManager = MiraiEventManager.getInstance();
this.taskManager = MiraiTaskManager.getInstance(); this.taskManager = MiraiTaskManager.getInstance();
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + (isUnix()?"unix":"windows") ); getLogger().info(LoggerTextFormat.SKY_BLUE + "About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + (isUnix() ? "unix" : "windows"));
this.getLogger().log("Loading data under " + LoggerTextFormat.GREEN + this.parentFolder); getLogger().info("Loading data under " + LoggerTextFormat.GREEN + this.parentFolder);
File setting = new File(this.parentFolder + "/Mirai.ini"); File setting = new File(this.parentFolder + "/Mirai.ini");
...@@ -91,10 +88,10 @@ public class MiraiServer { ...@@ -91,10 +88,10 @@ public class MiraiServer {
/* /*
MiraiMapSection qqs = this.setting.getMapSection("qq"); MiraiMapSection qqs = this.setting.getMapSection("qq");
qqs.forEach((a,p) -> { qqs.forEach((a,p) -> {
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "Finding available ports between " + "1-65536"); this.getLogger().info(LoggerTextFormat.SKY_BLUE + "Finding available ports between " + "1-65536");
try { try {
int port = MiraiNetwork.getAvailablePort(); int port = MiraiNetwork.getAvailablePort();
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "Listening on port " + port); this.getLogger().info(LoggerTextFormat.SKY_BLUE + "Listening on port " + port);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -120,11 +117,11 @@ public class MiraiServer { ...@@ -120,11 +117,11 @@ public class MiraiServer {
} }
public void initSetting(File setting){ public void initSetting(File setting){
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "Thanks for using Mirai"); getLogger().info(LoggerTextFormat.SKY_BLUE + "Thanks for using Mirai");
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "initializing Settings"); getLogger().info(LoggerTextFormat.SKY_BLUE + "initializing Settings");
try { try {
if(setting.createNewFile()){ if(setting.createNewFile()){
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "Mirai Config Created"); getLogger().info(LoggerTextFormat.SKY_BLUE + "Mirai Config Created");
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -134,13 +131,13 @@ public class MiraiServer { ...@@ -134,13 +131,13 @@ public class MiraiServer {
MiraiMapSection qqs = this.setting.getMapSection("qq"); MiraiMapSection qqs = this.setting.getMapSection("qq");
Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in);
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "input one " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.SKY_BLUE +"for default robot"); getLogger().info(LoggerTextFormat.SKY_BLUE + "input one " + LoggerTextFormat.RED + " QQ number " + LoggerTextFormat.SKY_BLUE + "for default robot");
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "输入用于默认机器人的QQ号"); getLogger().info(LoggerTextFormat.SKY_BLUE + "输入用于默认机器人的QQ号");
long qqNumber = scanner.nextLong(); long qqNumber = scanner.nextLong();
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "input the password for that QQ account"); getLogger().info(LoggerTextFormat.SKY_BLUE + "input the password for that QQ account");
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "输入该QQ号对应密码"); getLogger().info(LoggerTextFormat.SKY_BLUE + "输入该QQ号对应密码");
String qqPassword = scanner.next(); String qqPassword = scanner.next();
this.getLogger().log(LoggerTextFormat.SKY_BLUE + "initialized; changing can be made in config file: " + setting.toString()); getLogger().info(LoggerTextFormat.SKY_BLUE + "initialized; changing can be made in config file: " + setting.toString());
qqs.put(String.valueOf(qqNumber),qqPassword); qqs.put(String.valueOf(qqNumber),qqPassword);
this.setting.save(); this.setting.save();
} }
...@@ -148,8 +145,8 @@ public class MiraiServer { ...@@ -148,8 +145,8 @@ public class MiraiServer {
private void onEnable(){ private void onEnable(){
this.eventManager.boardcastEvent(new ServerEnableEvent()); this.eventManager.boardcastEvent(new ServerEnableEvent());
this.enabled = true; this.enabled = true;
this.getLogger().log(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai"); getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai");
this.getLogger().log( "Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION); getLogger().info("Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION);
} }
......
package net.mamoe.mirai.contact
/**
* A contact is a QQ account or a QQ Group.
*
* @author Him188moe @ Mirai Project
*/
abstract class Contact(number: Long) {
/**
* Async
*/
abstract fun sendMessage(message: String)
/**
* Async
*/
abstract fun sendObjectMessage(message: String)
}
package net.mamoe.mirai.contact
class Group(number: Long) : Contact(number) {
init {
Instances.groups.add(this)
}
override fun sendMessage(message: String) {
}
override fun sendObjectMessage(message: String) {
}
}
package net.mamoe.mirai.contact
fun Long.asQQ(): QQ = Instances.qqs.stream().filter { t: QQ? -> t?.number?.equals(this)!! }.findAny().orElse(QQ(this))!!
fun Long.asGroup(): Group = Instances.groups.stream().filter { t: Group? -> t?.number?.equals(this)!! }.findAny().orElse(Group(this))!!
fun String.withImage(id: String, type: String) = "{$id}.$type"
object Instances {
var qqs = arrayListOf<QQ>()
var groups = arrayListOf<Group>()
}
package net.mamoe.mirai.contact
/**
* @author Him188moe @ Mirai Project
*/
class QQ(number: Long) : Contact(number) {
init {
Instances.qqs.add(this)
}
override fun sendMessage(message: String) {
}
override fun sendObjectMessage(message: String) {
}
/**
* At(@) this account.
*/
open fun at(): String {
return "[@" + this.number + "]"
}
}
package net.mamoe.mirai.event; package net.mamoe.mirai.event;
import lombok.AllArgsConstructor;
import lombok.Data;
import net.mamoe.mirai.event.events.Cancellable;
import net.mamoe.mirai.event.events.MiraiEvent; import net.mamoe.mirai.event.events.MiraiEvent;
import java.util.*; import java.util.*;
......
package net.mamoe.mirai.event.events; package net.mamoe.mirai.event.events;
import lombok.Getter;
public interface Cancellable { public interface Cancellable {
boolean isCancelled(); boolean isCancelled();
void setCancelled(); void cancel(boolean forceCancel);
void setCancelled(boolean forceCancel); void cancel();
} }
package net.mamoe.mirai.event.events; package net.mamoe.mirai.event.events;
import net.mamoe.mirai.event.events.Cancellable;
import net.mamoe.mirai.utils.EventException; import net.mamoe.mirai.utils.EventException;
public abstract class MiraiEvent { public abstract class MiraiEvent {
...@@ -14,11 +13,11 @@ public abstract class MiraiEvent { ...@@ -14,11 +13,11 @@ public abstract class MiraiEvent {
return this.cancelled; return this.cancelled;
} }
public void setCancelled() { public void cancel() {
setCancelled(true); cancel(true);
} }
public void setCancelled(boolean value) { public void cancel(boolean value) {
if (!(this instanceof Cancellable)) { if (!(this instanceof Cancellable)) {
throw new EventException("Event is not Cancellable"); throw new EventException("Event is not Cancellable");
} }
......
package net.mamoe.mirai.event.events.robot
import net.mamoe.mirai.event.events.MiraiEvent
import net.mamoe.mirai.network.Robot
/**
* @author Him188moe @ Mirai Project
*/
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
}
}
package net.mamoe.mirai.network
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import lombok.extern.log4j.Log4j2
import net.mamoe.mirai.MiraiServer
import net.mamoe.mirai.network.packet.server.ServerPacket
/**
* @author Him188moe @ Mirai Project
*/
@Log4j2
class ClientHandler(val robot: Robot) : SimpleChannelInboundHandler<ByteArray>() {
override fun channelRead0(ctx: ChannelHandlerContext?, bytes: ByteArray?) {
try {
robot.onPacketReceived(ServerPacket.ofByteArray(bytes))
} catch (e: Exception) {
MiraiServer.getLogger().catching(e)
}
}
override fun channelActive(ctx: ChannelHandlerContext) {
println("Successfully connected to server")
}
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
MiraiServer.getLogger().catching(cause)
}
}
\ No newline at end of file
package net.mamoe.mirai.network; package net.mamoe.mirai.network;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.Bootstrap;
import lombok.Getter; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
public class MiraiNetwork { public class MiraiNetwork {
public static void connect(String host, int port) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println("connected server...");
ch.pipeline().addLast(new ByteArrayEncoder());
ch.pipeline().addLast(new ByteArrayDecoder());
ch.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture cf = b.connect().sync();
@Getter cf.channel().closeFuture().sync();
private static volatile Throwable lastError = null; } finally {
group.shutdownGracefully().sync();
public static void start(int port){ }
} }
...@@ -26,5 +49,4 @@ public class MiraiNetwork { ...@@ -26,5 +49,4 @@ public class MiraiNetwork {
} }
} }
package net.mamoe.mirai.network; package net.mamoe.mirai.network;
import net.mamoe.mirai.MiraiServer; import lombok.extern.log4j.Log4j2;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.net.DatagramPacket;
import java.net.*; import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@Log4j2
public class MiraiUDPClient { public class MiraiUDPClient {
private DatagramSocket localUDPSocket; private DatagramSocket localUDPSocket;
private Thread thread; private Thread thread;
public MiraiUDPClient(InetAddress target, int targetPort, int localPort) { public MiraiUDPClient(InetAddress target, int targetPort, int localPort) {
MiraiServer.getInstance().getLogger().log("creating client"); log.info("creating client");
try{ try{
this.localUDPSocket = new DatagramSocket(localPort); this.localUDPSocket = new DatagramSocket(localPort);
this.localUDPSocket.connect(target,targetPort); this.localUDPSocket.connect(target,targetPort);
this.localUDPSocket.setReuseAddress(true); this.localUDPSocket.setReuseAddress(true);
this.thread = new Thread(() -> { this.thread = new Thread(() -> {
try { try {
while (true) while (true) {
{
byte[] data = new byte[1024]; byte[] data = new byte[1024];
// 接收数据报的包 // 接收数据报的包
DatagramPacket packet = new DatagramPacket(data, data.length); DatagramPacket packet = new DatagramPacket(data, data.length);
...@@ -39,8 +41,9 @@ public class MiraiUDPClient { ...@@ -39,8 +41,9 @@ public class MiraiUDPClient {
} catch (SocketException e) { } catch (SocketException e) {
e.printStackTrace(); e.printStackTrace();
} }
MiraiServer.getInstance().getLogger().log("created client"); log.info("created client");
} }
public void onReceive(DatagramPacket packet){ public void onReceive(DatagramPacket packet){
System.out.println(new String(packet.getData(), 0 , packet.getLength(), StandardCharsets.UTF_8)); System.out.println(new String(packet.getData(), 0 , packet.getLength(), StandardCharsets.UTF_8));
} }
......
...@@ -9,13 +9,13 @@ import io.netty.channel.SimpleChannelInboundHandler; ...@@ -9,13 +9,13 @@ import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.dns.DatagramDnsQueryDecoder;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import net.mamoe.mirai.MiraiServer; import lombok.extern.log4j.Log4j2;
@Log4j2
public class MiraiUDPServer { public class MiraiUDPServer {
public MiraiUDPServer() { public MiraiUDPServer() {
MiraiServer.getInstance().getLogger().log("creating server"); log.info("creating server");
new Thread(() -> { new Thread(() -> {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
...@@ -25,7 +25,7 @@ public class MiraiUDPServer { ...@@ -25,7 +25,7 @@ public class MiraiUDPServer {
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet)
throws Exception { throws Exception {
// 读取收到的数据 // 读取收到的数据
ByteBuf buf = (ByteBuf) packet.copy().content(); ByteBuf buf = packet.copy().content();
byte[] req = new byte[buf.readableBytes()]; byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req); buf.readBytes(req);
String body = new String(req, CharsetUtil.UTF_8); String body = new String(req, CharsetUtil.UTF_8);
...@@ -46,6 +46,6 @@ public class MiraiUDPServer { ...@@ -46,6 +46,6 @@ public class MiraiUDPServer {
e.printStackTrace(); e.printStackTrace();
} }
}).start(); }).start();
MiraiServer.getInstance().getLogger().log("created server"); log.info("created server");
} }
} }
package net.mamoe.mirai.network
import net.mamoe.mirai.network.packet.Packet
import net.mamoe.mirai.network.packet.server.ServerPacket
/**
* @author Him188moe @ Mirai Project
*/
open class Robot() {
internal fun onPacketReceived(packet: Packet) {
if (packet !is ServerPacket) {
return;
}
packet.decode()
}
}
\ No newline at end of file
...@@ -25,7 +25,7 @@ public class ClientLoginPacket extends ClientPacket { ...@@ -25,7 +25,7 @@ public class ClientLoginPacket extends ClientPacket {
//TEA 加密 //TEA 加密
var data = new ClientPacket() { this.write(TEAEncryption.encrypt(new ClientPacket() {
@Override @Override
public void encode() throws IOException { public void encode() throws IOException {
this.writeHex(Protocol._0825data0); this.writeHex(Protocol._0825data0);
...@@ -36,9 +36,6 @@ public class ClientLoginPacket extends ClientPacket { ...@@ -36,9 +36,6 @@ public class ClientLoginPacket extends ClientPacket {
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);
} }
}; }.encodeToByteArray(), Protocol.hexToBytes(Protocol._0825key)));
data.encode();
this.write(TEAEncryption.encrypt(data.toByteArray(), Protocol.hexToBytes(Protocol._0825key)));
} }
} }
...@@ -74,4 +74,10 @@ public abstract class ClientPacket extends DataOutputStream implements Packet { ...@@ -74,4 +74,10 @@ public abstract class ClientPacket extends DataOutputStream implements Packet {
public byte[] toByteArray() { public byte[] toByteArray() {
return ((ByteArrayOutputStream) this.out).toByteArray(); return ((ByteArrayOutputStream) this.out).toByteArray();
} }
public final byte[] encodeToByteArray() throws IOException {
encode();
return toByteArray();
}
} }
...@@ -11,6 +11,11 @@ import java.io.InputStream; ...@@ -11,6 +11,11 @@ import java.io.InputStream;
* @author Him188moe @ Mirai Project * @author Him188moe @ Mirai Project
*/ */
public abstract class ServerPacket extends DataInputStream implements Packet { public abstract class ServerPacket extends DataInputStream implements Packet {
public static ServerPacket ofByteArray(byte[] bytes) {
// TODO: 2019/8/15 process bytes
}
public ServerPacket(@NotNull InputStream in) { public ServerPacket(@NotNull InputStream in) {
super(in); super(in);
} }
......
package net.mamoe.mirai.qq;
public class QQ {
}
package net.mamoe.mirai.qq;
public class QQGroup {
}
package net.mamoe.mirai.qq;
public class QQMessage {
}
...@@ -5,7 +5,7 @@ public interface MiraiTaskExceptionHandler { ...@@ -5,7 +5,7 @@ public interface MiraiTaskExceptionHandler {
void onHandle(Throwable e); void onHandle(Throwable e);
static MiraiTaskExceptionHandler byDefault(){ static MiraiTaskExceptionHandler byDefault(){
return Throwable::printStackTrace; return byPrint();
} }
static MiraiTaskExceptionHandler byIgnore(){ static MiraiTaskExceptionHandler byIgnore(){
......
package net.mamoe.mirai.utils;
import net.mamoe.mirai.MiraiServer;
import net.mamoe.mirai.task.MiraiTaskManager;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MiraiLogger {
private static MiraiLogger instance;
public static MiraiLogger getInstance(){
if(MiraiLogger.instance == null){
MiraiLogger.instance = new MiraiLogger();
}
return MiraiLogger.instance;
}
public void log(Object o){
this.log(o.toString());
}
public void log(String s){
System.out.println("[" + new SimpleDateFormat("MM-dd HH:mm:ss").format(new Date()) + "] Mirai: " + s + LoggerTextFormat.RESET);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment