diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/BasePacketHandler.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/BasePacketHandler.java deleted file mode 100644 index b71f9ce..0000000 --- a/src/main/java/me/unlegitdqrk/fakeminecraftserver/BasePacketHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -package me.unlegitdqrk.fakeminecraftserver; - -import com.google.gson.Gson; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import me.unlegitdqrk.fakeminecraftserver.streams.MojewInputStream; -import me.unlegitdqrk.fakeminecraftserver.streams.MojewOutputStream; - - -/** - * @author UnlegitDqrk - */ - -public class BasePacketHandler extends ChannelInboundHandlerAdapter { - private final Gson gson = new Gson(); - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - MojewInputStream inputStream = new MojewInputStream((ByteBuf) msg); - - // handshake - int length = inputStream.readInt(); - int id = inputStream.readInt(); - - if (id == 0) { - // status request - try { - int version = inputStream.readInt(); - String address = inputStream.readUTF(); - int port = inputStream.readUnsignedShort(); - int state = inputStream.readInt(); - System.out.println("Received request: " + length + ", " + id + ", " + version + ", " + address + ", " + port + ", " + state); - } catch (Exception ignored) { - // status request packet is sent inconsistently, so we ignore it - } - - inputStream.close(); - - // status response - String response = gson.toJson(FakeMinecraftServer.response).replace(ChatConverter.ESCAPE + "", "\\u00A7"); // Mojew's parser needs this escaped (classic) - - if (FakeMinecraftServer.response.favicon == null) - System.out.println("Sending response: " + response); - else - System.out.println("Sent response with image data."); - - MojewOutputStream outputStream = new MojewOutputStream(Unpooled.buffer()); - MojewOutputStream dataOutputStream = new MojewOutputStream(Unpooled.buffer()); - - dataOutputStream.writeInt(0); - dataOutputStream.writeUTF(response); - dataOutputStream.close(); - - outputStream.writeInt(dataOutputStream.writtenBytes()); - outputStream.write(dataOutputStream.getData()); - outputStream.close(); - - ctx.writeAndFlush(outputStream.buffer()); - } else if (id == 1) { - // ping request - long time = inputStream.readLong(); - System.out.println("Received ping packet: " + length + ", " + id + ", " + time); - - // ping response - MojewOutputStream outputStream = new MojewOutputStream(Unpooled.buffer()); - MojewOutputStream dataOutputStream = new MojewOutputStream(Unpooled.buffer()); - - dataOutputStream.writeInt(1); - dataOutputStream.writeLong(time); - dataOutputStream.close(); - - outputStream.writeInt(dataOutputStream.writtenBytes()); - outputStream.write(dataOutputStream.getData()); - outputStream.close(); - - ctx.writeAndFlush(outputStream.buffer()); - } else if (id == 2) { - // TODO: Fixing kick message - - // login attempt - System.out.println("Received login packet: " + length + ", " + id); - - // login response - MojewOutputStream outputStream = new MojewOutputStream(Unpooled.buffer()); - MojewOutputStream dataOutputStream = new MojewOutputStream(Unpooled.buffer()); - - dataOutputStream.writeInt(2); - dataOutputStream.writeUTF("{text:\""+ ChatConverter.replaceColors(FakeMinecraftServer.KICK_MESSAGE).replace("\\n", "\n") + "\", color: white}"); - dataOutputStream.close(); - - outputStream.writeInt(dataOutputStream.writtenBytes()); - outputStream.write(dataOutputStream.getData()); - outputStream.close(); - - ctx.writeAndFlush(outputStream.buffer()); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - cause.printStackTrace(); - ctx.close(); - } -} diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/FakeMinecraftServer.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/FakeMinecraftServer.java index 0676b3a..b07530c 100644 --- a/src/main/java/me/unlegitdqrk/fakeminecraftserver/FakeMinecraftServer.java +++ b/src/main/java/me/unlegitdqrk/fakeminecraftserver/FakeMinecraftServer.java @@ -1,67 +1,120 @@ package me.unlegitdqrk.fakeminecraftserver; import me.unlegitdqrk.fakeminecraftserver.data.StatusResponse; +import me.unlegitdqrk.fakeminecraftserver.network.ResponderThread; +import javax.imageio.ImageIO; import javax.xml.bind.DatatypeConverter; import java.awt.image.BufferedImage; -import java.io.*; -import java.util.*; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.net.ServerSocket; import static javax.imageio.ImageIO.read; -import static javax.imageio.ImageIO.write; /** * @author UnlegitDqrk */ public class FakeMinecraftServer { - public static StatusResponse response = null; - - public static final int START_PORT = 25565; - - public static final String ENGINE = "classic"; - - public static final int MAX_PLAYERS = 100; - public static final int ONLINE_PLAYERS = 10; - - public static final int PROTOCOL_VERSION = 47; - public static final String PROTOCOL_TEXT = "1.8.8"; - - public static final String MOTD_LINE1 = "&4Ein fake Minecraftserver"; - public static final String MOTD_LINE2 = "&cDeveloped by UnlegitDqrk"; - - public static final String KICK_MESSAGE = "&4Just a Fakeserver!\n&aDeveloped by UnlegitDqrk"; - public static final List SAMPLES = Arrays.asList("&4Fakeserver", "&5by", "&aUnlegitDqrk"); + private static StatusResponse response = null; + private static boolean stopping = false; + private static ServerSocket server; public static final File SERVER_ICON = new File("server-icon.png"); public static void start() throws Exception { - System.out.println("ChatConverter class by md_5: Copyright (c) 2012, md_5. All rights reserved."); - String serverIconAsString = null; + System.out.println("Starting server..."); + printCredits(); - if (SERVER_ICON.exists()) { - BufferedImage image = read(SERVER_ICON); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - write(image, "png", baos); - serverIconAsString = "data:image/png;base64," + DatatypeConverter.printBase64Binary(baos.toByteArray()); - } else System.err.println("Starting fake server without icon!"); + response = new StatusResponse(Settings.PROTOCOL_TEXT, Settings.PROTOCOL_VERSION, + Settings.MAX_PLAYERS, Settings.ONLINE_PLAYERS, + getDescription(), loadServerIcon()); - String motd = MOTD_LINE1 + "\n" + MOTD_LINE2; - - Message description; - - if (ENGINE.equalsIgnoreCase("json")) - description = ChatConverter.toJSONChat(ChatConverter.replaceColors(motd).replace("\\n", "\n")); - else { - description = new Message(); - description.text = ChatConverter.replaceColors(motd).replace("\\n", "\n"); - } - - response = new StatusResponse(PROTOCOL_TEXT, PROTOCOL_VERSION, - MAX_PLAYERS, ONLINE_PLAYERS, - description, serverIconAsString); - - new SLPServer(START_PORT).run(); + addShutdownHook(); + startServer(); } + private static void printCredits() { + System.out.println("ChatConverter class by md_5: Copyright (c) 2012, md_5. All rights reserved."); + System.out.println("ByteBufUtils class by Spout LLC: Copyright (c) 2013 Spout LLC "); + } + + public static StatusResponse getResponse() { + return response; + } + + private static String loadServerIcon() throws IOException { + if (!SERVER_ICON.exists()) { + System.err.println("No server-icon was found!"); + return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAADIjAAAyIwHN55PYAAA50WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS41LWMwMTQgNzkuMTUxNDgxLCAyMDEzLzAzLzEzLTEyOjA5OjE1ICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpPC94bXA6Q3JlYXRvclRvb2w+CiAgICAgICAgIDx4bXA6Q3JlYXRlRGF0ZT4yMDE0LTA1LTMxVDAzOjAyOjI2KzAyOjAwPC94bXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNC0wNS0zMVQwMzowMjoyNiswMjowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMTQtMDUtMzFUMDM6MDI6MjYrMDI6MDA8L3htcDpNb2RpZnlEYXRlPgogICAgICAgICA8eG1wTU06SW5zdGFuY2VJRD54bXAuaWlkOjMwMzZiNjc2LThmZDYtNTI0Mi05MjE0LWQ5YzYzZTQ2MmRiYjwveG1wTU06SW5zdGFuY2VJRD4KICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+eG1wLmRpZDplOGMwNGViMy01ZGQ1LTAwNDAtODc5Ny0yNThkZjRiZmVlOTg8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+eG1wLmRpZDplOGMwNGViMy01ZGQ1LTAwNDAtODc5Ny0yNThkZjRiZmVlOTg8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ZThjMDRlYjMtNWRkNS0wMDQwLTg3OTctMjU4ZGY0YmZlZTk4PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTA1LTMxVDAzOjAyOjI2KzAyOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDozMDM2YjY3Ni04ZmQ2LTUyNDItOTIxNC1kOWM2M2U0NjJkYmI8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTQtMDUtMzFUMDM6MDI6MjYrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpTZXE+CiAgICAgICAgIDwveG1wTU06SGlzdG9yeT4KICAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9wbmc8L2RjOmZvcm1hdD4KICAgICAgICAgPHBob3Rvc2hvcDpDb2xvck1vZGU+MzwvcGhvdG9zaG9wOkNvbG9yTW9kZT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+MzI2MDAwMC8xMDAwMDwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6WVJlc29sdXRpb24+MzI2MDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PjB4J1kAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAGhJREFUeNrs0AEBAAAEAzD073w92CKsk9RnU88JECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgIALFgAA//8DAFW2A3065VKgAAAAAElFTkSuQmCC"; + } + + BufferedImage image = read(SERVER_ICON); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "png", baos); + return "data:image/png;base64," + DatatypeConverter.printBase64Binary(baos.toByteArray()); + } + + private static Message getDescription() { + String motd = Settings.MOTD_LINE1 + "\n" + Settings.MOTD_LINE2; + + if (Settings.ENGINE.equalsIgnoreCase("json")) + return ChatConverter.toJSONChat(ChatConverter.replaceColors(motd).replace("\\n", "\n")); + else { + Message description = new Message(); + description.text = ChatConverter.replaceColors(motd).replace("\\n", "\n"); + return description; + } + } + + private static void startServer() { + if (stopping) throw new IllegalAccessError(); + + try { + server = new ServerSocket(Settings.START_PORT, 5); + + while (!server.isClosed()) { + new ResponderThread(server.accept()).start(); + } + + } catch (Exception exception) { + if (!stopping) { + System.err.println("Failed to start server:"); + exception.printStackTrace(); + System.exit(0); + } + } finally { + stopServer(); + } + + } + + private static void addShutdownHook() { + Runtime.getRuntime().addShutdownHook(new Thread(() -> stopServer())); + } + + public static void stopServer() { + stopping = true; + + if (server == null) return; + + System.out.println("Stopping server..."); + + safeClose(server); + server = null; + + System.out.println("Server stopped."); + } + + public static void safeClose(final Closeable closeable) { + if (closeable == null) return; + + try { + closeable.close(); + } catch (Exception ignored) { + } + } } diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/SLPServer.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/SLPServer.java deleted file mode 100644 index e416629..0000000 --- a/src/main/java/me/unlegitdqrk/fakeminecraftserver/SLPServer.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.unlegitdqrk.fakeminecraftserver; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; - -/** - * @author UnlegitDqrk - */ - -public class SLPServer { - private int port; - - public SLPServer(int port) { - this.port = port; - } - - public void run() throws Exception { - EventLoopGroup bossGroup = new NioEventLoopGroup(); - EventLoopGroup workerGroup = new NioEventLoopGroup(); - - try { - ServerBootstrap serverBootstrap = new ServerBootstrap(); - serverBootstrap.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - public void initChannel(Channel channel) { - channel.pipeline().addLast(new BasePacketHandler()); - } - }).option(ChannelOption.SO_BACKLOG, 128) - .childOption(ChannelOption.SO_KEEPALIVE, true); - ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); - channelFuture.channel().closeFuture().sync(); - } finally { - workerGroup.shutdownGracefully(); - bossGroup.shutdownGracefully(); - } - } -} diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/Settings.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/Settings.java new file mode 100644 index 0000000..0da8bf8 --- /dev/null +++ b/src/main/java/me/unlegitdqrk/fakeminecraftserver/Settings.java @@ -0,0 +1,25 @@ +package me.unlegitdqrk.fakeminecraftserver; + +import java.util.Arrays; +import java.util.List; + +public class Settings { + + public static final int START_PORT = 25565; + + public static final String ENGINE = "classic"; + public static final int SOCKET_TIMEOUT_IN_SECONDS = 3; + + public static final int MAX_PLAYERS = 100; + public static final int ONLINE_PLAYERS = 10; + + public static final int PROTOCOL_VERSION = 47; + public static final String PROTOCOL_TEXT = "1.8.8"; + + public static final String MOTD_LINE1 = "&4Ein fake Minecraftserver"; + public static final String MOTD_LINE2 = "&cDeveloped by UnlegitDqrk"; + + public static final String KICK_MESSAGE = "&4Just a Fakeserver!\n&aDeveloped by UnlegitDqrk"; + public static final List SAMPLES = Arrays.asList("&4Fakeserver", "&5by", "&aUnlegitDqrk"); + +} diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/data/StatusResponse.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/data/StatusResponse.java index 1632b11..e2e1754 100644 --- a/src/main/java/me/unlegitdqrk/fakeminecraftserver/data/StatusResponse.java +++ b/src/main/java/me/unlegitdqrk/fakeminecraftserver/data/StatusResponse.java @@ -1,10 +1,12 @@ package me.unlegitdqrk.fakeminecraftserver.data; import me.unlegitdqrk.fakeminecraftserver.ChatConverter; -import me.unlegitdqrk.fakeminecraftserver.FakeMinecraftServer; import me.unlegitdqrk.fakeminecraftserver.Message; +import me.unlegitdqrk.fakeminecraftserver.Settings; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** * @author UnlegitDqrk @@ -44,7 +46,7 @@ public class StatusResponse { this.online = online; this.sample = new ArrayList<>(); - for (String sample : FakeMinecraftServer.SAMPLES) { + for (String sample : Settings.SAMPLES) { this.sample.add(new Sample(ChatConverter.replaceColors(sample))); } } diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/network/ByteBufUtils.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/network/ByteBufUtils.java new file mode 100644 index 0000000..ac1d052 --- /dev/null +++ b/src/main/java/me/unlegitdqrk/fakeminecraftserver/network/ByteBufUtils.java @@ -0,0 +1,113 @@ +package me.unlegitdqrk.fakeminecraftserver.network; + +/* + * This file is part of Flow Networking, licensed under the MIT License (MIT). + * + * Copyright (c) 2013 Spout LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + + +/** + * A class containing various utility methods that act on byte buffers. + */ +public class ByteBufUtils { + /** + * Reads an UTF8 string from a byte buffer. + * + * @param buf The byte buffer to read from + * @return The read string + * @throws java.io.IOException If the reading fails + */ + public static String readUTF8(DataInput buf) throws IOException { + // Read the string's length + final int len = readVarInt(buf); + final byte[] bytes = new byte[len]; + buf.readFully(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + + /** + * Writes an UTF8 string to a byte buffer. + * + * @param buf The byte buffer to write too + * @param value The string to write + * @throws java.io.IOException If the writing fails + */ + public static void writeUTF8(DataOutput buf, String value) throws IOException { + final byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + if (bytes.length >= Short.MAX_VALUE) { + throw new IOException("Attempt to write a string with a length greater than Short.MAX_VALUE to ByteBuf!"); + } + // Write the string's length + writeVarInt(buf, bytes.length); + buf.write(bytes); + } + + /** + * Reads an integer written into the byte buffer as one of various bit sizes. + * + * @param buf The byte buffer to read from + * @return The read integer + * @throws java.io.IOException If the reading fails + */ + public static int readVarInt(DataInput buf) throws IOException { + int out = 0; + int bytes = 0; + byte in; + while (true) { + in = buf.readByte(); + out |= (in & 0x7F) << (bytes * 7); + if (bytes > 32) { + throw new IOException("Attempt to read int bigger than allowed for a varint!"); + } + if ((in & 0x80) != 0x80) { + break; + } + } + return out; + } + + /** + * Writes an integer into the byte buffer using the least possible amount of bits. + * + * @param buf The byte buffer to write too + * @param value The integer value to write + */ + public static void writeVarInt(DataOutput buf, int value) throws IOException { + int part; + while (true) { + part = value & 0x7F; + value >>>= 7; + if (value != 0) { + part |= 0x80; + } + buf.writeByte(part); + if (value == 0) { + break; + } + } + } +} diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/network/ResponderThread.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/network/ResponderThread.java new file mode 100644 index 0000000..df21938 --- /dev/null +++ b/src/main/java/me/unlegitdqrk/fakeminecraftserver/network/ResponderThread.java @@ -0,0 +1,148 @@ +package me.unlegitdqrk.fakeminecraftserver.network; + +import com.google.gson.Gson; +import me.unlegitdqrk.fakeminecraftserver.ChatConverter; +import me.unlegitdqrk.fakeminecraftserver.FakeMinecraftServer; +import me.unlegitdqrk.fakeminecraftserver.Settings; + +import java.io.*; +import java.net.Socket; +import java.net.SocketException; +import java.net.SocketTimeoutException; + +/** + * @author UnlegitDqrk + */ + +public class ResponderThread extends Thread { + + private final Socket socket; + private final DataInputStream inputStream; + private final DataOutputStream outputStream; + private final String remoteHost; + private int clientProtocolVersion; + private Thread thread = null; + private boolean enabled = false; + + public ResponderThread(Socket socket) throws IOException { + this.socket = socket; + + this.inputStream = new DataInputStream(socket.getInputStream()); + this.outputStream = new DataOutputStream(socket.getOutputStream()); + + this.remoteHost = socket.getRemoteSocketAddress().toString().substring(1); + + socket.setSoTimeout(Settings.SOCKET_TIMEOUT_IN_SECONDS * 1000); + + this.enabled = true; + } + + @Override + public void run() { + this.thread = Thread.currentThread(); + boolean showMotd = false; + + try { + while (this.socket.isConnected() && this.enabled) { + final int length = ByteBufUtils.readVarInt(this.inputStream); + final int packetId = ByteBufUtils.readVarInt(this.inputStream); + + System.out.println("length: " + length + " packet id: " + packetId); + + if (length == 0) return; + + // handshake + if (packetId == 0) { + if (!showMotd) { + final int version = ByteBufUtils.readVarInt(this.inputStream); + @SuppressWarnings("unused") final String ip = ByteBufUtils.readUTF8(this.inputStream); + @SuppressWarnings("unused") final int port = this.inputStream.readUnsignedShort(); + final int state = ByteBufUtils.readVarInt(this.inputStream); + + System.out.println("(State request) length:" + length + " id:" + packetId + " version:" + version + " state:" + state); + clientProtocolVersion = version; + + // state 1=status 2=login + if (state == 1) { + // ping / status request + showMotd = true; + System.out.println("ping: " + this.remoteHost); + } else if (state == 2) { + // login attempt + writeData("{text:\"" + ChatConverter.replaceColors(Settings.KICK_MESSAGE) + "\", color: white}"); + System.out.println("Kick: " + this.remoteHost + " - " + Settings.KICK_MESSAGE); + return; + } + } else { + // info packet + System.out.println("(Info request) length:" + length + " id:" + packetId); + final String motd = createInfo(); + + if (motd == null || motd.isEmpty()) { + System.out.println("Info is not initialized!"); + return; + } + + writeData(motd); + showMotd = false; + } + } else if (packetId == 1) { + long receivedLong = this.inputStream.readLong(); + System.out.println("Pong: " + receivedLong); + + ByteBufUtils.writeVarInt(this.outputStream, 9); + ByteBufUtils.writeVarInt(this.outputStream, 1); + + this.outputStream.writeLong(receivedLong); + this.outputStream.flush(); + } else { + System.out.println("Unknown packet: " + packetId); + return; + } + } + } + // Ignore this unnecessary error + catch (EOFException ignored) { + System.out.println("(end of socket)"); + } catch (SocketTimeoutException ignored) { + System.out.println("(socket timeout)"); + } catch (SocketException ignored) { + System.out.println("(socket closed)"); + } catch (IOException exception) { + exception.printStackTrace(); + } finally { + closeSocket(); + this.thread = null; + } + } + + public final int getClientProtocolVersion() { + return clientProtocolVersion; + } + + private final void closeSocket() { + this.enabled = false; + + FakeMinecraftServer.safeClose(this.inputStream); + FakeMinecraftServer.safeClose(this.outputStream); + FakeMinecraftServer.safeClose(this.socket); + + if (this.thread != null) this.thread.interrupt(); + } + + private final void writeData(final String data) throws IOException { + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); + + ByteBufUtils.writeVarInt(dataOutputStream, 0); + ByteBufUtils.writeUTF8(dataOutputStream, data); + ByteBufUtils.writeVarInt(this.outputStream, byteArrayOutputStream.size()); + + this.outputStream.write(byteArrayOutputStream.toByteArray()); + this.outputStream.flush(); + } + + private final String createInfo() { + return new Gson().toJson(FakeMinecraftServer.getResponse()); + } +} diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/streams/MojewInputStream.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/streams/MojewInputStream.java deleted file mode 100644 index f278eaa..0000000 --- a/src/main/java/me/unlegitdqrk/fakeminecraftserver/streams/MojewInputStream.java +++ /dev/null @@ -1,37 +0,0 @@ -package me.unlegitdqrk.fakeminecraftserver.streams; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufInputStream; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -/** - * @author UnlegitDqrk - */ - -public class MojewInputStream extends ByteBufInputStream { - public MojewInputStream(ByteBuf buffer) { - super(buffer); - } - - @Override - public String readUTF() throws IOException { - byte[] input = new byte[readInt()]; - readFully(input); - return new String(input, StandardCharsets.UTF_8); - } - - @Override - public int readInt() throws IOException { - int i = 0; - int j = 0; - while (true) { - int k = readByte(); - i |= (k & 0x7F) << j++ * 7; - if (j > 5) throw new RuntimeException("VarInt too big"); - if ((k & 0x80) != 128) break; - } - return i; - } -} diff --git a/src/main/java/me/unlegitdqrk/fakeminecraftserver/streams/MojewOutputStream.java b/src/main/java/me/unlegitdqrk/fakeminecraftserver/streams/MojewOutputStream.java deleted file mode 100644 index 3d5f4ed..0000000 --- a/src/main/java/me/unlegitdqrk/fakeminecraftserver/streams/MojewOutputStream.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.unlegitdqrk.fakeminecraftserver.streams; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufOutputStream; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -/** - * @author UnlegitDqrk - */ - -public class MojewOutputStream extends ByteBufOutputStream { - public MojewOutputStream(ByteBuf buffer) { - super(buffer); - } - - @Override - public void writeUTF(String s) throws IOException { - byte[] data = s.getBytes(StandardCharsets.UTF_8); - writeInt(s.length()); - write(data); - } - - @Override - public void writeInt(int paramInt) throws IOException { - while (true) { - if ((paramInt & 0xFFFFFF80) == 0) { - writeByte(paramInt); - return; - } - writeByte(paramInt & 0x7F | 0x80); - paramInt >>>= 7; - } - } - - public byte[] getData() { - return Arrays.copyOfRange(buffer().array(), 0, writtenBytes()); - } -}