Bug fix
This commit is contained in:
@@ -0,0 +1,97 @@
|
|||||||
|
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) +", 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();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
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.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author UnlegitDqrk
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ChatConverter {
|
||||||
|
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[] chrarray = text.toCharArray();
|
||||||
|
for (int index = 0; index < chrarray.length; index++) {
|
||||||
|
char chr = chrarray[index];
|
||||||
|
if (chr != '&')
|
||||||
|
continue;
|
||||||
|
if ((index + 1) == chrarray.length)
|
||||||
|
break;
|
||||||
|
char forward = chrarray[index + 1];
|
||||||
|
if ((forward >= '0' && forward <= '9') || (forward >= 'a' && forward <= 'f') || (forward >= 'k' && forward <= 'r'))
|
||||||
|
chrarray[index] = ESCAPE;
|
||||||
|
}
|
||||||
|
return new String(chrarray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Message toJSONChat(String txt) {
|
||||||
|
Message msg = new Message();
|
||||||
|
ArrayList<Message> parts = new ArrayList<>();
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
Matcher matcher = url.matcher(txt);
|
||||||
|
for (int i = 0; i < txt.length(); i++) {
|
||||||
|
char c = txt.charAt(i);
|
||||||
|
if (c != COLOR_CHAR) {
|
||||||
|
int pos = txt.indexOf(' ', i);
|
||||||
|
if (pos == -1) pos = txt.length();
|
||||||
|
if (matcher.region(i, pos).find()) { //Web link handling
|
||||||
|
msg.text = buf.toString();
|
||||||
|
buf = new StringBuilder();
|
||||||
|
parts.add(msg);
|
||||||
|
Message old = msg;
|
||||||
|
msg = new Message(old);
|
||||||
|
msg.underlined = true;
|
||||||
|
msg.clickEvent = new ClickEvent();
|
||||||
|
msg.clickEvent.action = "open_url";
|
||||||
|
String urlString = txt.substring(i, pos);
|
||||||
|
msg.text = msg.clickEvent.value = urlString;
|
||||||
|
parts.add(msg);
|
||||||
|
i += pos - i - 1;
|
||||||
|
msg = new Message(old);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buf.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
c = txt.charAt(i);
|
||||||
|
if (c >= 'A' && c <= 'Z') {
|
||||||
|
c += 32;
|
||||||
|
}
|
||||||
|
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == 'r') {
|
||||||
|
msg.text = buf.toString();
|
||||||
|
buf = new StringBuilder();
|
||||||
|
parts.add(msg);
|
||||||
|
msg = new Message();
|
||||||
|
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
|
||||||
|
msg.color = Color.fromCode(Character.toString(c));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case 'k':
|
||||||
|
msg.obfuscated = true;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
msg.bold = true;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
msg.strikethrough = true;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
msg.underlined = true;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
msg.italic = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg.text = buf.toString();
|
||||||
|
parts.add(msg);
|
||||||
|
if (parts.get(0).text.equals(""))
|
||||||
|
parts.remove(0); // occasionally empty text?
|
||||||
|
Message base = parts.remove(0);
|
||||||
|
if (parts.size() != 0)
|
||||||
|
base.extra = new ArrayList<>(parts);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClickEvent {
|
||||||
|
public String action;
|
||||||
|
public String value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
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.*;
|
||||||
|
|
||||||
|
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<String> SAMPLES = Arrays.asList("&4Fakeserver", "&5by", "&aUnlegitDqrk");
|
||||||
|
|
||||||
|
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());
|
||||||
|
} else System.err.println("Starting fake server without icon!");
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
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 Color color;
|
||||||
|
|
||||||
|
public 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
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<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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
package me.unlegitdqrk.fakeminecraftserver.data;
|
||||||
|
|
||||||
|
import me.unlegitdqrk.fakeminecraftserver.ChatConverter;
|
||||||
|
import me.unlegitdqrk.fakeminecraftserver.FakeMinecraftServer;
|
||||||
|
import me.unlegitdqrk.fakeminecraftserver.Message;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author UnlegitDqrk
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class StatusResponse {
|
||||||
|
Version version;
|
||||||
|
Players players;
|
||||||
|
Message description;
|
||||||
|
|
||||||
|
public String favicon;
|
||||||
|
|
||||||
|
public StatusResponse(String name, int protocol, int max, int online, Message description,String favicon) {
|
||||||
|
this.version = new Version(name, protocol);
|
||||||
|
this.players = new Players(max, online);
|
||||||
|
this.description = description;
|
||||||
|
this.favicon = favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Version {
|
||||||
|
String name;
|
||||||
|
int protocol;
|
||||||
|
|
||||||
|
public Version(String name, int protocol) {
|
||||||
|
this.name = name;
|
||||||
|
this.protocol = protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Players {
|
||||||
|
int max;
|
||||||
|
int online;
|
||||||
|
List<Sample> sample;
|
||||||
|
|
||||||
|
Players(int max, int online) {
|
||||||
|
this.max = max;
|
||||||
|
this.online = online;
|
||||||
|
this.sample = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String sample : FakeMinecraftServer.SAMPLES) {
|
||||||
|
this.sample.add(new Sample(ChatConverter.replaceColors(sample)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sample {
|
||||||
|
String name;
|
||||||
|
String id;
|
||||||
|
|
||||||
|
Sample(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.id = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
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