Bug fix
This commit is contained in:
@@ -1,85 +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(StartFakeServer.response).replace(ColorConverter.ESCAPE + "", "\\u00A7"); // Mojew's parser needs this escaped (classic)
|
||||
|
||||
if (StartFakeServer.response.getServerIconAsString() == 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());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2012, md_5. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
You may not use the software for commercial software hosting services without
|
||||
written permission from the author.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package me.unlegitdqrk.fakeminecraftserver;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ColorConverter {
|
||||
private static final char COLOR_CHAR = '\u00A7';
|
||||
private static final Pattern url = Pattern.compile("^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$");
|
||||
public static final char ESCAPE = '\u00A7';
|
||||
|
||||
public static String replaceColors(String text) {
|
||||
char[] charArray = text.toCharArray();
|
||||
|
||||
for (int index = 0; index < charArray.length; index++) {
|
||||
char chr = charArray[index];
|
||||
if (chr != '&') continue;
|
||||
if ((index + 1) == charArray.length) break;
|
||||
|
||||
char forward = charArray[index + 1];
|
||||
|
||||
if ((forward >= '0' && forward <= '9') || (forward >= 'a' && forward <= 'f')
|
||||
|| (forward >= 'k' && forward <= 'r')) charArray[index] = ESCAPE;
|
||||
}
|
||||
return new String(charArray);
|
||||
}
|
||||
|
||||
public class ClickEvent {
|
||||
public String action;
|
||||
public String value;
|
||||
}
|
||||
|
||||
public enum Color {
|
||||
@SerializedName("black")
|
||||
BLACK("0"),
|
||||
@SerializedName("dark_blue")
|
||||
DARK_BLUE("1"),
|
||||
@SerializedName("dark_green")
|
||||
DARK_GREEN("2"),
|
||||
@SerializedName("dark_aqua")
|
||||
DARK_AQUA("3"),
|
||||
@SerializedName("dark_red")
|
||||
DARK_RED("4"),
|
||||
@SerializedName("purple")
|
||||
DARK_PURPLE("5"),
|
||||
@SerializedName("gold")
|
||||
GOLD("6"),
|
||||
@SerializedName("gray")
|
||||
GRAY("7"),
|
||||
@SerializedName("dark_gray")
|
||||
DARK_GRAY("8"),
|
||||
@SerializedName("blue")
|
||||
BLUE("9"),
|
||||
@SerializedName("green")
|
||||
GREEN("a"),
|
||||
@SerializedName("aqua")
|
||||
AQUA("b"),
|
||||
@SerializedName("red")
|
||||
RED("c"),
|
||||
@SerializedName("light_purple")
|
||||
LIGHT_PURPLE("d"),
|
||||
@SerializedName("yellow")
|
||||
YELLOW("e"),
|
||||
@SerializedName("white")
|
||||
WHITE("f");
|
||||
|
||||
public String code;
|
||||
|
||||
Color(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
private static HashMap<String, Color> codeMap = new HashMap<>();
|
||||
|
||||
public static Color fromCode(String code) {
|
||||
return codeMap.get(code);
|
||||
}
|
||||
|
||||
static {
|
||||
for (Color color : values()) {
|
||||
codeMap.put(color.code, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,34 +0,0 @@
|
||||
package me.unlegitdqrk.fakeminecraftserver;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author UnlegitDqrk
|
||||
*/
|
||||
|
||||
public class Message {
|
||||
public String text;
|
||||
|
||||
public boolean bold;
|
||||
public boolean italic;
|
||||
public boolean underlined;
|
||||
public boolean strikethrough;
|
||||
public boolean obfuscated;
|
||||
public List<Message> extra;
|
||||
|
||||
public ColorConverter.Color color;
|
||||
|
||||
public ColorConverter.ClickEvent clickEvent;
|
||||
|
||||
public Message() {
|
||||
|
||||
}
|
||||
|
||||
public Message(Message old) {
|
||||
this.bold = old.bold;
|
||||
this.italic = old.italic;
|
||||
this.underlined = old.underlined;
|
||||
this.strikethrough = old.strikethrough;
|
||||
this.color = old.color;
|
||||
}
|
||||
}
|
@@ -1,45 +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 int getPort() {
|
||||
return 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<Channel>() {
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
package me.unlegitdqrk.fakeminecraftserver;
|
||||
|
||||
import me.unlegitdqrk.fakeminecraftserver.data.StatusResponse;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static javax.imageio.ImageIO.read;
|
||||
import static javax.imageio.ImageIO.write;
|
||||
|
||||
/**
|
||||
* @author UnlegitDqrk
|
||||
*/
|
||||
|
||||
public class StartFakeServer {
|
||||
public static StatusResponse response = null;
|
||||
|
||||
public static final int START_PORT = 25565;
|
||||
|
||||
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 List<String> SAMPLES = Arrays.asList("&cSample 1", "&bSample 2", "&aSample 3");
|
||||
public static final File SERVER_ICON = new File("server-icon.png");
|
||||
|
||||
public static void start() throws Exception {
|
||||
String serverIconAsString = null;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
Message description = new Message();
|
||||
String motd = MOTD_LINE1 + "\n" + MOTD_LINE2;
|
||||
description.text = ColorConverter.replaceColors(motd).replace("\\n", "\n");
|
||||
|
||||
response = new StatusResponse(ColorConverter.replaceColors(PROTOCOL_TEXT), PROTOCOL_VERSION,
|
||||
MAX_PLAYERS, ONLINE_PLAYERS,
|
||||
description, serverIconAsString);
|
||||
|
||||
new SLPServer(START_PORT).run();
|
||||
}
|
||||
|
||||
}
|
@@ -1,73 +0,0 @@
|
||||
package me.unlegitdqrk.fakeminecraftserver.data;
|
||||
|
||||
import me.unlegitdqrk.fakeminecraftserver.Message;
|
||||
|
||||
/**
|
||||
* @author UnlegitDqrk
|
||||
*/
|
||||
|
||||
public class StatusResponse {
|
||||
private final Version version;
|
||||
private final Players players;
|
||||
private final Message description;
|
||||
private final String serverIconAsString;
|
||||
|
||||
public Message getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Players getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
public String getServerIconAsString() {
|
||||
return serverIconAsString;
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public StatusResponse(String name, int protocol, int max, int online, Message description, String serverIconAsString) {
|
||||
this.version = new Version(name, protocol);
|
||||
this.players = new Players(max, online);
|
||||
this.description = description;
|
||||
this.serverIconAsString = serverIconAsString;
|
||||
}
|
||||
|
||||
public class Version {
|
||||
private final String name;
|
||||
private final int protocol;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public Version(String name, int protocol) {
|
||||
this.name = name;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
||||
|
||||
private class Players {
|
||||
private final int maxPlayers;
|
||||
private final int onlinePlayers;
|
||||
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
public int getOnlinePlayers() {
|
||||
return onlinePlayers;
|
||||
}
|
||||
|
||||
private Players(int maxPlayers, int onlinePlayers) {
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.onlinePlayers = onlinePlayers;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,41 +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;
|
||||
}
|
||||
}
|
@@ -1,42 +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());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user