forked from BLOCKFANTASY/LOOHP-Limbo
Support Bungeecord IP forwarding
This commit is contained in:
parent
c2077a2a5c
commit
b01cbad932
|
|
@ -9,6 +9,7 @@ import java.io.PrintStream;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import com.loohp.limbo.Player.Player;
|
import com.loohp.limbo.Player.Player;
|
||||||
import com.loohp.limbo.Utils.CustomStringUtils;
|
import com.loohp.limbo.Utils.CustomStringUtils;
|
||||||
|
|
@ -71,6 +72,72 @@ public class Console {
|
||||||
super(out);
|
super(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintStream printf(Locale l, String format, Object... args) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
return super.printf(l, "[" + date + "] " + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintStream printf(String format, Object... args) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
return super.printf("[" + date + "] " + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println() {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(boolean x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(char x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(char[] x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + String.valueOf(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(double x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(float x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(int x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(long x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(Object x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
super.println("[" + date + "] " + x);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void println(String string) {
|
public void println(String string) {
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ public class ServerProperties {
|
||||||
String motdJson;
|
String motdJson;
|
||||||
String versionString;
|
String versionString;
|
||||||
int protocol;
|
int protocol;
|
||||||
|
boolean bungeecord;
|
||||||
|
|
||||||
Optional<BufferedImage> favicon;
|
Optional<BufferedImage> favicon;
|
||||||
|
|
||||||
|
|
@ -63,6 +64,7 @@ public class ServerProperties {
|
||||||
allowFlight = Boolean.parseBoolean(prop.getProperty("allow-flight"));
|
allowFlight = Boolean.parseBoolean(prop.getProperty("allow-flight"));
|
||||||
motdJson = prop.getProperty("motd");
|
motdJson = prop.getProperty("motd");
|
||||||
versionString = prop.getProperty("version");
|
versionString = prop.getProperty("version");
|
||||||
|
bungeecord = Boolean.parseBoolean(prop.getProperty("bungeecord"));
|
||||||
|
|
||||||
File png = new File("server-icon.png");
|
File png = new File("server-icon.png");
|
||||||
if (png.exists()) {
|
if (png.exists()) {
|
||||||
|
|
@ -84,6 +86,10 @@ public class ServerProperties {
|
||||||
System.out.println("Loaded server.properties");
|
System.out.println("Loaded server.properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBungeecord() {
|
||||||
|
return bungeecord;
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<BufferedImage> getFavicon() {
|
public Optional<BufferedImage> getFavicon() {
|
||||||
return favicon;
|
return favicon;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ public class Limbo {
|
||||||
base = base.replace("%PROTOCOL%", String.valueOf(properties.getProtocol()));
|
base = base.replace("%PROTOCOL%", String.valueOf(properties.getProtocol()));
|
||||||
base = base.replace("%MOTD%", properties.getMotdJson());
|
base = base.replace("%MOTD%", properties.getMotdJson());
|
||||||
base = base.replace("%MAXPLAYERS%", String.valueOf(properties.getMaxPlayers()));
|
base = base.replace("%MAXPLAYERS%", String.valueOf(properties.getMaxPlayers()));
|
||||||
base = base.replace("%ONLINECLIENTS%", String.valueOf(server.getClients().size()));
|
base = base.replace("%ONLINECLIENTS%", String.valueOf(getPlayers().size()));
|
||||||
|
|
||||||
if (properties.getFavicon().isPresent()) {
|
if (properties.getFavicon().isPresent()) {
|
||||||
String icon = "\"favicon\":\"data:image/png;base64," + ImageUtils.imgToBase64String(properties.getFavicon().get(), "png") + "\",";
|
String icon = "\"favicon\":\"data:image/png;base64," + ImageUtils.imgToBase64String(properties.getFavicon().get(), "png") + "\",";
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.loohp.limbo.Server;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -16,6 +17,7 @@ import com.loohp.limbo.Player.Player;
|
||||||
import com.loohp.limbo.Server.Packets.Packet;
|
import com.loohp.limbo.Server.Packets.Packet;
|
||||||
import com.loohp.limbo.Server.Packets.PacketHandshakingIn;
|
import com.loohp.limbo.Server.Packets.PacketHandshakingIn;
|
||||||
import com.loohp.limbo.Server.Packets.PacketLoginInLoginStart;
|
import com.loohp.limbo.Server.Packets.PacketLoginInLoginStart;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketLoginOutDisconnect;
|
||||||
import com.loohp.limbo.Server.Packets.PacketLoginOutLoginSuccess;
|
import com.loohp.limbo.Server.Packets.PacketLoginOutLoginSuccess;
|
||||||
import com.loohp.limbo.Server.Packets.PacketOut;
|
import com.loohp.limbo.Server.Packets.PacketOut;
|
||||||
import com.loohp.limbo.Server.Packets.PacketPlayInChat;
|
import com.loohp.limbo.Server.Packets.PacketPlayInChat;
|
||||||
|
|
@ -42,8 +44,8 @@ import com.loohp.limbo.Server.Packets.PacketStatusOutPong;
|
||||||
import com.loohp.limbo.Server.Packets.PacketStatusOutResponse;
|
import com.loohp.limbo.Server.Packets.PacketStatusOutResponse;
|
||||||
import com.loohp.limbo.Utils.CustomStringUtils;
|
import com.loohp.limbo.Utils.CustomStringUtils;
|
||||||
import com.loohp.limbo.Utils.DataTypeIO;
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
import com.loohp.limbo.Utils.SkinUtils;
|
import com.loohp.limbo.Utils.MojangAPIUtils;
|
||||||
import com.loohp.limbo.Utils.SkinUtils.SkinResponse;
|
import com.loohp.limbo.Utils.MojangAPIUtils.SkinResponse;
|
||||||
import com.loohp.limbo.World.BlockPosition;
|
import com.loohp.limbo.World.BlockPosition;
|
||||||
import com.loohp.limbo.World.DimensionRegistry;
|
import com.loohp.limbo.World.DimensionRegistry;
|
||||||
import com.loohp.limbo.World.World;
|
import com.loohp.limbo.World.World;
|
||||||
|
|
@ -73,8 +75,15 @@ public class ClientConnection extends Thread {
|
||||||
|
|
||||||
private DataOutputStream output;
|
private DataOutputStream output;
|
||||||
|
|
||||||
|
private InetAddress iNetAddress;
|
||||||
|
|
||||||
public ClientConnection(Socket client_socket) {
|
public ClientConnection(Socket client_socket) {
|
||||||
this.client_socket = client_socket;
|
this.client_socket = client_socket;
|
||||||
|
this.iNetAddress = client_socket.getInetAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetAddress getiNetAddress() {
|
||||||
|
return iNetAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastKeepAlivePayLoad() {
|
public long getLastKeepAlivePayLoad() {
|
||||||
|
|
@ -124,6 +133,23 @@ public class ClientConnection extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void disconnectDuringLogin(BaseComponent[] reason) {
|
||||||
|
try {
|
||||||
|
PacketLoginOutDisconnect packet = new PacketLoginOutDisconnect(ComponentSerializer.toString(reason));
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
|
output.write(packetByte);
|
||||||
|
output.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
client_socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
running = true;
|
running = true;
|
||||||
|
|
@ -133,8 +159,17 @@ public class ClientConnection extends Thread {
|
||||||
DataInputStream input = new DataInputStream(client_socket.getInputStream());
|
DataInputStream input = new DataInputStream(client_socket.getInputStream());
|
||||||
output = new DataOutputStream(client_socket.getOutputStream());
|
output = new DataOutputStream(client_socket.getOutputStream());
|
||||||
DataTypeIO.readVarInt(input);
|
DataTypeIO.readVarInt(input);
|
||||||
int handShakeId = DataTypeIO.readVarInt(input);
|
|
||||||
PacketHandshakingIn handshake = (PacketHandshakingIn) Packet.getHandshakeIn().get(handShakeId).getConstructor(DataInputStream.class).newInstance(input);
|
//int handShakeId = DataTypeIO.readVarInt(input);
|
||||||
|
DataTypeIO.readVarInt(input);
|
||||||
|
|
||||||
|
PacketHandshakingIn handshake = new PacketHandshakingIn(input);
|
||||||
|
|
||||||
|
boolean isBungeecord = Limbo.getInstance().getServerProperties().isBungeecord();
|
||||||
|
String bungeeForwarding = handshake.getServerAddress();
|
||||||
|
UUID bungeeUUID = null;
|
||||||
|
SkinResponse bungeeSkin = null;
|
||||||
|
|
||||||
switch (handshake.getHandshakeType()) {
|
switch (handshake.getHandshakeType()) {
|
||||||
case STATUS:
|
case STATUS:
|
||||||
state = ClientState.STATUS;
|
state = ClientState.STATUS;
|
||||||
|
|
@ -146,7 +181,7 @@ public class ClientConnection extends Thread {
|
||||||
//do nothing
|
//do nothing
|
||||||
} else if (packetType.equals(PacketStatusInRequest.class)) {
|
} else if (packetType.equals(PacketStatusInRequest.class)) {
|
||||||
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
|
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
|
||||||
System.out.println("[/" + str + "] <-> InitialHandler has pinged");
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Handshake Status has pinged");
|
||||||
PacketStatusOutResponse packet = new PacketStatusOutResponse(Limbo.getInstance().getServerListResponseJson());
|
PacketStatusOutResponse packet = new PacketStatusOutResponse(Limbo.getInstance().getServerListResponseJson());
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
} else if (packetType.equals(PacketStatusInPing.class)) {
|
} else if (packetType.equals(PacketStatusInPing.class)) {
|
||||||
|
|
@ -159,6 +194,27 @@ public class ClientConnection extends Thread {
|
||||||
break;
|
break;
|
||||||
case LOGIN:
|
case LOGIN:
|
||||||
state = ClientState.LOGIN;
|
state = ClientState.LOGIN;
|
||||||
|
|
||||||
|
if (isBungeecord) {
|
||||||
|
try {
|
||||||
|
String[] data = bungeeForwarding.split("\\x00");
|
||||||
|
//String host = data[0];
|
||||||
|
String ip = data[1];
|
||||||
|
|
||||||
|
bungeeUUID = UUID.fromString(data[2].replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
|
||||||
|
iNetAddress = InetAddress.getByName(ip);
|
||||||
|
|
||||||
|
String skinJson = data[3];
|
||||||
|
|
||||||
|
String skin = skinJson.split("\"value\":\"")[1].split("\"")[0];
|
||||||
|
String signature = skinJson.split("\"signature\":\"")[1].split("\"")[0];
|
||||||
|
bungeeSkin = new SkinResponse(skin, signature);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("If you wish to use bungeecord's IP forwarding, please enable that in your bungeecord config.yml as well!");
|
||||||
|
disconnectDuringLogin(new BaseComponent[] {new TextComponent(ChatColor.RED + "Please connect from the proxy!")});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (client_socket.isConnected()) {
|
while (client_socket.isConnected()) {
|
||||||
int size = DataTypeIO.readVarInt(input);
|
int size = DataTypeIO.readVarInt(input);
|
||||||
int packetId = DataTypeIO.readVarInt(input);
|
int packetId = DataTypeIO.readVarInt(input);
|
||||||
|
|
@ -169,7 +225,8 @@ public class ClientConnection extends Thread {
|
||||||
} else if (packetType.equals(PacketLoginInLoginStart.class)) {
|
} else if (packetType.equals(PacketLoginInLoginStart.class)) {
|
||||||
PacketLoginInLoginStart start = new PacketLoginInLoginStart(input);
|
PacketLoginInLoginStart start = new PacketLoginInLoginStart(input);
|
||||||
String username = start.getUsername();
|
String username = start.getUsername();
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
|
UUID uuid = isBungeecord ? bungeeUUID : UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username);
|
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username);
|
||||||
sendPacket(success);
|
sendPacket(success);
|
||||||
|
|
||||||
|
|
@ -216,7 +273,7 @@ public class ClientConnection extends Thread {
|
||||||
player.setLocation(new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
|
player.setLocation(new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
|
||||||
sendPacket(positionLook);
|
sendPacket(positionLook);
|
||||||
|
|
||||||
SkinResponse skinresponce = SkinUtils.getSkinFromMojangServer(player.getName());
|
SkinResponse skinresponce = isBungeecord ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
|
||||||
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
|
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
|
||||||
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUUID(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
|
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUUID(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
|
||||||
sendPacket(info);
|
sendPacket(info);
|
||||||
|
|
@ -240,7 +297,7 @@ public class ClientConnection extends Thread {
|
||||||
sendPacket(abilities);
|
sendPacket(abilities);
|
||||||
|
|
||||||
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
||||||
System.out.println("[/" + str + "] <-> Player had connected to the Limbo server!");
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had connected to the Limbo server!");
|
||||||
|
|
||||||
while (client_socket.isConnected()) {
|
while (client_socket.isConnected()) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -272,7 +329,7 @@ public class ClientConnection extends Thread {
|
||||||
} else if (packetType.equals(PacketPlayInKeepAlive.class)) {
|
} else if (packetType.equals(PacketPlayInKeepAlive.class)) {
|
||||||
PacketPlayInKeepAlive alive = new PacketPlayInKeepAlive(input);
|
PacketPlayInKeepAlive alive = new PacketPlayInKeepAlive(input);
|
||||||
if (alive.getPayload() != lastKeepAlivePayLoad) {
|
if (alive.getPayload() != lastKeepAlivePayLoad) {
|
||||||
System.out.println("Incorrect Payload recieved in KeepAlive packet for player " + player.getName());
|
Limbo.getInstance().getConsole().sendMessage("Incorrect Payload recieved in KeepAlive packet for player " + player.getName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (packetType.equals(PacketPlayInChat.class)) {
|
} else if (packetType.equals(PacketPlayInChat.class)) {
|
||||||
|
|
@ -299,7 +356,7 @@ public class ClientConnection extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
||||||
System.out.println("[/" + str + "] <-> Player had disconnected!");
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had disconnected!");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {}
|
} catch (Exception e) {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketLoginInPluginMessaging extends PacketIn {
|
||||||
|
|
||||||
|
private int messageId;
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketLoginInPluginMessaging(int messageId, NamespacedKey channel, byte[] data) {
|
||||||
|
this.messageId = messageId;
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketLoginInPluginMessaging(DataInputStream in, int packetLength, int packetId) throws IOException {
|
||||||
|
messageId = DataTypeIO.readVarInt(in);
|
||||||
|
String rawChannel = DataTypeIO.readString(in);
|
||||||
|
channel = new NamespacedKey(rawChannel);
|
||||||
|
int dataLength = packetLength - DataTypeIO.getVarIntLength(packetId) - DataTypeIO.getVarIntLength(messageId) - DataTypeIO.getStringLength(rawChannel, StandardCharsets.UTF_8);
|
||||||
|
data = new byte[dataLength];
|
||||||
|
in.read(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketLoginOutPluginMessaging extends PacketOut {
|
||||||
|
|
||||||
|
private int messageId;
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketLoginOutPluginMessaging(int messageId, NamespacedKey channel, byte[] data) {
|
||||||
|
this.messageId = messageId;
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getLoginOut().get(getClass()));
|
||||||
|
DataTypeIO.writeVarInt(output, messageId);
|
||||||
|
DataTypeIO.writeString(output, channel.toString(), StandardCharsets.UTF_8);
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketPlayInPluginMessaging extends PacketIn {
|
||||||
|
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketPlayInPluginMessaging(NamespacedKey channel, byte[] data) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInPluginMessaging(DataInputStream in, int packetLength, int packetId) throws IOException {
|
||||||
|
String rawChannel = DataTypeIO.readString(in);
|
||||||
|
channel = new NamespacedKey(rawChannel);
|
||||||
|
int dataLength = packetLength - DataTypeIO.getVarIntLength(packetId) - DataTypeIO.getStringLength(rawChannel, StandardCharsets.UTF_8);
|
||||||
|
data = new byte[dataLength];
|
||||||
|
in.read(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketPlayOutPluginMessaging extends PacketOut {
|
||||||
|
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketPlayOutPluginMessaging(NamespacedKey channel, byte[] data) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeString(output, channel.toString(), StandardCharsets.UTF_8);
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.google.common.io.ByteArrayDataInput;
|
||||||
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPluginMessaging;
|
||||||
|
|
||||||
|
public class BungeeLoginMessageUtils {
|
||||||
|
|
||||||
|
public static void sendUUIDRequest(DataOutputStream output) throws IOException {
|
||||||
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||||
|
out.writeUTF("UUID");
|
||||||
|
|
||||||
|
PacketPlayOutPluginMessaging packet = new PacketPlayOutPluginMessaging(new NamespacedKey("bungeecord", "main"), out.toByteArray());
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
|
output.write(packetByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID readUUIDResponse(byte[] data) {
|
||||||
|
ByteArrayDataInput in = ByteStreams.newDataInput(data);
|
||||||
|
String subchannel = in.readUTF();
|
||||||
|
if (subchannel.equals("UUID")) {
|
||||||
|
return UUID.fromString(in.readUTF());
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Bungeecord Message receieved is not an IP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendIPRequest(DataOutputStream output) throws IOException {
|
||||||
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||||
|
out.writeUTF("IP");
|
||||||
|
|
||||||
|
PacketPlayOutPluginMessaging packet = new PacketPlayOutPluginMessaging(new NamespacedKey("bungeecord", "main"), out.toByteArray());
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
|
output.write(packetByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InetAddress readIPResponse(byte[] data) throws UnknownHostException {
|
||||||
|
ByteArrayDataInput in = ByteStreams.newDataInput(data);
|
||||||
|
String subchannel = in.readUTF();
|
||||||
|
if (subchannel.equals("IP")) {
|
||||||
|
String ip = in.readUTF();
|
||||||
|
in.readInt();
|
||||||
|
return InetAddress.getByName(ip);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Bungeecord Message receieved is not an IP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,11 @@ public class DataTypeIO {
|
||||||
return new String(b);
|
return new String(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getStringLength(String string, Charset charset) throws IOException {
|
||||||
|
byte[] bytes = string.getBytes(charset);
|
||||||
|
return bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
public static void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
|
public static void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
|
||||||
byte[] bytes = string.getBytes(charset);
|
byte[] bytes = string.getBytes(charset);
|
||||||
writeVarInt(out, bytes.length);
|
writeVarInt(out, bytes.length);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
public class SkinUtils {
|
public class MojangAPIUtils {
|
||||||
|
|
||||||
public static class SkinResponse {
|
public static class SkinResponse {
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ public class SkinUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkinResponse getSkinFromMojangServer(String username) {
|
public static UUID getOnlineUUIDOfPlayerFromMojang(String username) {
|
||||||
try {
|
try {
|
||||||
URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + username);
|
URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + username);
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||||
|
|
@ -42,8 +42,12 @@ public class SkinUtils {
|
||||||
connection.addRequestProperty("Pragma", "no-cache");
|
connection.addRequestProperty("Pragma", "no-cache");
|
||||||
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
||||||
String reply = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine();
|
String reply = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine();
|
||||||
|
if (!reply.contains("\"error\":\"BadRequestException\"")) {
|
||||||
String uuid = reply.split("\"id\":\"")[1].split("\"")[0];
|
String uuid = reply.split("\"id\":\"")[1].split("\"")[0];
|
||||||
return getSkinFromMojangServer(UUID.fromString(uuid.replaceFirst( "([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5" )));
|
return UUID.fromString(uuid.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
System.out.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
|
System.out.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -54,6 +58,14 @@ public class SkinUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SkinResponse getSkinFromMojangServer(String username) {
|
||||||
|
UUID uuid = getOnlineUUIDOfPlayerFromMojang(username);
|
||||||
|
if (uuid == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getSkinFromMojangServer(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
public static SkinResponse getSkinFromMojangServer(UUID uuid) {
|
public static SkinResponse getSkinFromMojangServer(UUID uuid) {
|
||||||
try {
|
try {
|
||||||
URL url = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid.toString() + "?unsigned=false");
|
URL url = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid.toString() + "?unsigned=false");
|
||||||
|
|
@ -3,18 +3,21 @@
|
||||||
"0x00": "PacketHandshakingIn"
|
"0x00": "PacketHandshakingIn"
|
||||||
},
|
},
|
||||||
"LoginIn": {
|
"LoginIn": {
|
||||||
"0x00": "PacketLoginInLoginStart"
|
"0x00": "PacketLoginInLoginStart",
|
||||||
|
"0x02": "PacketLoginInPluginMessaging"
|
||||||
},
|
},
|
||||||
"LoginOut": {
|
"LoginOut": {
|
||||||
"PacketLoginOutLoginSuccess": "0x02",
|
"PacketLoginOutLoginSuccess": "0x02",
|
||||||
"PacketLoginOutDisconnect": "0x00"
|
"PacketLoginOutDisconnect": "0x00",
|
||||||
|
"PacketLoginOutPluginMessaging": "0x04",
|
||||||
},
|
},
|
||||||
"PlayIn": {
|
"PlayIn": {
|
||||||
"0x10": "PacketPlayInKeepAlive",
|
"0x10": "PacketPlayInKeepAlive",
|
||||||
"0x03": "PacketPlayInChat",
|
"0x03": "PacketPlayInChat",
|
||||||
"0x13": "PacketPlayInPositionAndLook",
|
"0x13": "PacketPlayInPositionAndLook",
|
||||||
"0x12": "PacketPlayInPosition",
|
"0x12": "PacketPlayInPosition",
|
||||||
"0x14": "PacketPlayInRotation"
|
"0x14": "PacketPlayInRotation",
|
||||||
|
"0x0B": "PacketPlayInPluginMessaging"
|
||||||
},
|
},
|
||||||
"PlayOut": {
|
"PlayOut": {
|
||||||
"PacketPlayOutLogin": "0x25",
|
"PacketPlayOutLogin": "0x25",
|
||||||
|
|
@ -27,7 +30,8 @@
|
||||||
"PacketPlayOutPlayerInfo": "0x33",
|
"PacketPlayOutPlayerInfo": "0x33",
|
||||||
"PacketPlayOutUpdateViewPosition": "0x40",
|
"PacketPlayOutUpdateViewPosition": "0x40",
|
||||||
"PacketPlayOutShowPlayerSkins": "0x44",
|
"PacketPlayOutShowPlayerSkins": "0x44",
|
||||||
"PacketPlayOutDisconnect": "0x1A"
|
"PacketPlayOutDisconnect": "0x1A",
|
||||||
|
"PacketPlayOutPluginMessaging": "0x17"
|
||||||
},
|
},
|
||||||
"StatusIn": {
|
"StatusIn": {
|
||||||
"0x01": "PacketStatusInPing",
|
"0x01": "PacketStatusInPing",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ server-port=30000
|
||||||
#Server ip, localhost for local access only
|
#Server ip, localhost for local access only
|
||||||
server-ip=localhost
|
server-ip=localhost
|
||||||
|
|
||||||
|
#Whether this is server is behind a bungeecord proxy
|
||||||
|
bungeecord=true
|
||||||
|
|
||||||
#World Name and the Schematic file containing map
|
#World Name and the Schematic file containing map
|
||||||
level-name=world;spawn.schem
|
level-name=world;spawn.schem
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue