mirror of
https://github.com/ayunami2000/ayungee.git
synced 2024-11-09 06:36:05 -08:00
make it actually connect servers now :D
crazy right??!?!?!???!
This commit is contained in:
parent
75423d4ea5
commit
9c9d3c28eb
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
web
|
web
|
||||||
target/*
|
target/*
|
||||||
!target/ayungee-1.0-SNAPSHOT-jar-with-dependencies.jar
|
!target/ayungee-1.0-SNAPSHOT-jar-with-dependencies.jar
|
||||||
|
test
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
lightweight bungeecord alternative for eaglercraft servers running protocolsupport
|
lightweight bungeecord alternative for eaglercraft servers running protocolsupport
|
||||||
|
|
||||||
Thanks to LAX1DUDE for very small snippets of EaglerBungee used in this project (specifically for the server icon)
|
Thanks to LAX1DUDE and md-5 for very small snippets of EaglerBungee used in this project (specifically for the server icon, skins, & entity remapping)
|
||||||
|
|
||||||
**TODO: skins & capes**
|
**TODO: ability for plugins to change a player's server & built-in auth system**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**if you have questions about the license, please, reach out to me. i just put the license i put on most of my projects on this, but if you have a problem with it, let me know.
|
||||||
|
|
|
@ -16,10 +16,17 @@ public class Client {
|
||||||
|
|
||||||
public String username;
|
public String username;
|
||||||
|
|
||||||
|
public int server = 0;
|
||||||
|
|
||||||
|
public byte[] handshake = null;
|
||||||
|
|
||||||
|
public int clientEntityId;
|
||||||
|
public int serverEntityId;
|
||||||
|
|
||||||
public void setSocket(Socket sock) throws IOException {
|
public void setSocket(Socket sock) throws IOException {
|
||||||
socket = sock;
|
socket = sock;
|
||||||
socketOut = sock.getOutputStream();
|
socketOut = sock.getOutputStream();
|
||||||
socketIn = socket.getInputStream();
|
socketIn = sock.getInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client(String uname) {
|
public Client(String uname) {
|
||||||
|
|
81
src/main/java/me/ayunami2000/ayungee/EntityMap.java
Normal file
81
src/main/java/me/ayunami2000/ayungee/EntityMap.java
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package me.ayunami2000.ayungee;
|
||||||
|
|
||||||
|
// https://github.com/LAX1DUDE/eaglercraft/blob/a8d5c856de28ba2a263abc055d7b26d50dc2bf7e/eaglercraftbungee/src/main/java/net/md_5/bungee/EntityMap.java
|
||||||
|
|
||||||
|
public class EntityMap {
|
||||||
|
public static final int[][] entityIds;
|
||||||
|
|
||||||
|
public static void rewrite(final byte[] packet, final int oldId, final int newId) {
|
||||||
|
final int packetId = packet[0] & 0xFF;
|
||||||
|
if (packetId == 29) {
|
||||||
|
for (int pos = 2; pos < (short) ((packet[1] << 8) + packet[2] & 0xff); pos += 4) {
|
||||||
|
final int readId = readInt(packet, pos);
|
||||||
|
if (readId == oldId) {
|
||||||
|
setInt(packet, pos, newId);
|
||||||
|
} else if (readId == newId) {
|
||||||
|
setInt(packet, pos, oldId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final int[] idArray = EntityMap.entityIds[packetId];
|
||||||
|
if (idArray != null) {
|
||||||
|
for (final int pos2 : idArray) {
|
||||||
|
final int readId2 = readInt(packet, pos2);
|
||||||
|
if (readId2 == oldId) {
|
||||||
|
setInt(packet, pos2, newId);
|
||||||
|
} else if (readId2 == newId) {
|
||||||
|
setInt(packet, pos2, oldId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (packetId == 23) {
|
||||||
|
final int type = packet[5] & 0xFF;
|
||||||
|
if (type == 60 || type == 90) {
|
||||||
|
final int index20 = readInt(packet, 20);
|
||||||
|
if (packet.length > 24 && index20 == oldId) {
|
||||||
|
setInt(packet, 20, newId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setInt(final byte[] buf, final int pos, final int i) {
|
||||||
|
buf[pos] = (byte) (i >> 24);
|
||||||
|
buf[pos + 1] = (byte) (i >> 16);
|
||||||
|
buf[pos + 2] = (byte) (i >> 8);
|
||||||
|
buf[pos + 3] = (byte) i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int readInt(final byte[] buf, final int pos) {
|
||||||
|
return (buf[pos] & 0xFF) << 24 | (buf[pos + 1] & 0xFF) << 16 | (buf[pos + 2] & 0xFF) << 8 | (buf[pos + 3] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
(entityIds = new int[256][])[5] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[7] = new int[] { 1, 5 };
|
||||||
|
EntityMap.entityIds[17] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[18] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[19] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[20] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[22] = new int[] { 1, 5 };
|
||||||
|
EntityMap.entityIds[23] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[24] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[25] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[26] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[28] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[30] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[31] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[32] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[33] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[34] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[35] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[38] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[39] = new int[] { 1, 5 };
|
||||||
|
EntityMap.entityIds[40] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[41] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[42] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[55] = new int[] { 1 };
|
||||||
|
EntityMap.entityIds[71] = new int[] { 1 };
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,9 +7,7 @@ import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.*;
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
@ -19,8 +17,7 @@ import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static String hostname = "localhost";
|
public static List<ServerItem> servers = new ArrayList<>();
|
||||||
public static int port = 25569;
|
|
||||||
public static int webPort = 25565;
|
public static int webPort = 25565;
|
||||||
|
|
||||||
public static String motdJson = "";
|
public static String motdJson = "";
|
||||||
|
@ -28,8 +25,6 @@ public class Main {
|
||||||
|
|
||||||
public static boolean forwarded = false;
|
public static boolean forwarded = false;
|
||||||
|
|
||||||
public static boolean eaglerPackets = false;
|
|
||||||
|
|
||||||
public static WebSocketServer webSocketServer = null;
|
public static WebSocketServer webSocketServer = null;
|
||||||
|
|
||||||
public static Map<WebSocket, Client> clients = new HashMap<>();
|
public static Map<WebSocket, Client> clients = new HashMap<>();
|
||||||
|
@ -107,12 +102,19 @@ public class Main {
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
servers.add(new ServerItem("localhost", 25569));
|
||||||
|
|
||||||
|
List<String> stringServers = (List<String>) config.getOrDefault("servers", new ArrayList<>());
|
||||||
|
|
||||||
|
if (!stringServers.isEmpty()) {
|
||||||
|
servers.clear();
|
||||||
|
for (String serverEntry : stringServers) {
|
||||||
|
servers.add(new ServerItem(serverEntry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hostname = (String) config.getOrDefault("hostname", "localhost");
|
|
||||||
port = (int) config.getOrDefault("port", 25569);
|
|
||||||
webPort = (int) config.getOrDefault("web_port", 25565);
|
webPort = (int) config.getOrDefault("web_port", 25565);
|
||||||
forwarded = (boolean) config.getOrDefault("forwarded", false);
|
forwarded = (boolean) config.getOrDefault("forwarded", false);
|
||||||
eaglerPackets = (boolean) config.getOrDefault("eag_packets", false);
|
|
||||||
|
|
||||||
List<String> defaultMotd = new ArrayList<>();
|
List<String> defaultMotd = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -168,7 +170,7 @@ public class Main {
|
||||||
switch (pieces[0]) {
|
switch (pieces[0]) {
|
||||||
case "help":
|
case "help":
|
||||||
case "?":
|
case "?":
|
||||||
System.out.println("help ; unban <ip> ; banip <ip> ; ban <username> ; stop");
|
System.out.println("help ; unban <ip> ; banip <ip> ; ban <username> ; send <username> <serverid> ; stop");
|
||||||
break;
|
break;
|
||||||
case "unban":
|
case "unban":
|
||||||
case "pardon":
|
case "pardon":
|
||||||
|
@ -229,6 +231,24 @@ public class Main {
|
||||||
System.out.println("IP " + pieces[1] + " is already banned!");
|
System.out.println("IP " + pieces[1] + " is already banned!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "send":
|
||||||
|
case "server":
|
||||||
|
if (pieces.length == 1 || pieces.length == 2) {
|
||||||
|
System.out.println("Usage: " + pieces[0] + " <username> <serverindex>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Client targetUser = clients.values().stream().filter(client -> client.username.equals(pieces[1])).findFirst().orElse(clients.values().stream().filter(client -> client.username.equalsIgnoreCase(pieces[1])).findFirst().orElse(null));
|
||||||
|
if (targetUser == null) {
|
||||||
|
System.out.println("Unable to find any user with that username!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int destServer = Integer.parseInt(pieces[2]);
|
||||||
|
targetUser.server = Math.max(0, Math.min(servers.size() - 1, destServer));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.out.println("That is not a valid number!");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "stop":
|
case "stop":
|
||||||
case "end":
|
case "end":
|
||||||
case "exit":
|
case "exit":
|
||||||
|
|
17
src/main/java/me/ayunami2000/ayungee/ServerItem.java
Normal file
17
src/main/java/me/ayunami2000/ayungee/ServerItem.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package me.ayunami2000.ayungee;
|
||||||
|
|
||||||
|
public class ServerItem {
|
||||||
|
public String host;
|
||||||
|
public int port = 25565;
|
||||||
|
|
||||||
|
public ServerItem(String h, int p) {
|
||||||
|
host = h;
|
||||||
|
port = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerItem(String hp) {
|
||||||
|
String[] pieces = hp.split(":");
|
||||||
|
if (pieces.length > 1) port = Integer.parseInt(pieces[1]);
|
||||||
|
host = pieces[0];
|
||||||
|
}
|
||||||
|
}
|
115
src/main/java/me/ayunami2000/ayungee/Skins.java
Normal file
115
src/main/java/me/ayunami2000/ayungee/Skins.java
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package me.ayunami2000.ayungee;
|
||||||
|
|
||||||
|
import org.java_websocket.WebSocket;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class Skins {
|
||||||
|
private static final HashMap<String,byte[]> skinCollection = new HashMap();
|
||||||
|
private static final HashMap<String,byte[]> capeCollection = new HashMap();
|
||||||
|
private static final HashMap<String,Long> lastSkinLayerUpdate = new HashMap();
|
||||||
|
|
||||||
|
private static final int[] SKIN_DATA_SIZE = new int[] { 64*32*4, 64*64*4, -9, -9, 1, 64*64*4, -9 }; // 128 pixel skins crash clients
|
||||||
|
private static final int[] CAPE_DATA_SIZE = new int[] { 32*32*4, -9, 1 };
|
||||||
|
|
||||||
|
public static boolean setSkin(String user, WebSocket conn, byte[] initMsg) {
|
||||||
|
if(initMsg.length >= 3) {
|
||||||
|
try {
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(initMsg);
|
||||||
|
bb.get();
|
||||||
|
int tagLen = bb.getShort();
|
||||||
|
if (!(tagLen >= 0 && tagLen < initMsg.length - 1)) return false;
|
||||||
|
StringBuilder tagBuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < tagLen; i++) tagBuilder.append(bb.getChar());
|
||||||
|
//int dataLen = bb.getShort();
|
||||||
|
int dataLen = bb.remaining() - 2;
|
||||||
|
String tag = tagBuilder.toString();
|
||||||
|
int offset = 3 + tagLen * 2 + 2;
|
||||||
|
byte[] msg = new byte[dataLen];
|
||||||
|
System.arraycopy(initMsg, offset, msg, 0, dataLen);
|
||||||
|
if("EAG|MySkin".equals(tag)) {
|
||||||
|
if(!skinCollection.containsKey(user)) {
|
||||||
|
int t = (int)msg[0] & 0xFF;
|
||||||
|
if(t >= 0 && t < SKIN_DATA_SIZE.length && msg.length == (SKIN_DATA_SIZE[t] + 1)) {
|
||||||
|
skinCollection.put(user, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if("EAG|MyCape".equals(tag)) {
|
||||||
|
if(!capeCollection.containsKey(user)) {
|
||||||
|
int t = (int)msg[0] & 0xFF;
|
||||||
|
if(t >= 0 && t < CAPE_DATA_SIZE.length && msg.length == (CAPE_DATA_SIZE[t] + 2)) {
|
||||||
|
capeCollection.put(user, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if("EAG|FetchSkin".equals(tag)) {
|
||||||
|
if(msg.length > 2) {
|
||||||
|
String fetch = new String(msg, 2, msg.length - 2, StandardCharsets.UTF_8);
|
||||||
|
byte[] data;
|
||||||
|
if((data = skinCollection.get(fetch)) != null) {
|
||||||
|
byte[] conc = new byte[data.length + 2];
|
||||||
|
conc[0] = msg[0]; conc[1] = msg[1]; //synchronization cookie
|
||||||
|
System.arraycopy(data, 0, conc, 2, data.length);
|
||||||
|
if((data = capeCollection.get(fetch)) != null) {
|
||||||
|
byte[] conc2 = new byte[conc.length + data.length];
|
||||||
|
System.arraycopy(conc, 0, conc2, 0, conc.length);
|
||||||
|
System.arraycopy(data, 0, conc2, conc.length, data.length);
|
||||||
|
conc = conc2;
|
||||||
|
}
|
||||||
|
byte[] packetPrefix = new byte[] { (byte) 250, 0, 12, 0, 69, 0, 65, 0, 71, 0, 124, 0, 85, 0, 115, 0, 101, 0, 114, 0, 83, 0, 107, 0, 105, 0, 110, (byte) ((conc.length >>> 8) & 0xFF), (byte) (conc.length & 0xFF) };
|
||||||
|
byte[] fullPacket = new byte[packetPrefix.length + conc.length];
|
||||||
|
System.arraycopy(packetPrefix, 0, fullPacket, 0, packetPrefix.length);
|
||||||
|
System.arraycopy(conc, 0, fullPacket, packetPrefix.length, conc.length);
|
||||||
|
conn.send(fullPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if("EAG|SkinLayers".equals(tag)) {
|
||||||
|
long millis = System.currentTimeMillis();
|
||||||
|
Long lsu = lastSkinLayerUpdate.get(user);
|
||||||
|
if(lsu != null && millis - lsu.longValue() < 700l) { // DoS protection
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lastSkinLayerUpdate.put(user, millis);
|
||||||
|
byte[] data;
|
||||||
|
if((data = capeCollection.get(user)) != null) {
|
||||||
|
data[1] = msg[0];
|
||||||
|
}else {
|
||||||
|
data = new byte[] { (byte)2, msg[0], (byte)0 };
|
||||||
|
capeCollection.put(user, data);
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dd = new DataOutputStream(bao);
|
||||||
|
dd.write(msg[0]);
|
||||||
|
dd.writeUTF(user);
|
||||||
|
byte[] bpacket = bao.toByteArray();
|
||||||
|
byte[] packetPrefix = new byte[] { (byte) 250, 0, 14, 0, 69, 0, 65, 0, 71, 0, 124, 0, 83, 0, 107, 0, 105, 0, 110, 0, 76, 0, 97, 0, 121, 0, 101, 0, 114, 0, 115, (byte) ((bpacket.length >>> 8) & 0xFF), (byte) (bpacket.length & 0xFF) };
|
||||||
|
int off = bpacket.length == 0 ? 2 : 0;
|
||||||
|
byte[] fullPacket = new byte[(packetPrefix.length - off) + bpacket.length];
|
||||||
|
System.arraycopy(packetPrefix, 0, fullPacket, 0, packetPrefix.length - off);
|
||||||
|
if (bpacket.length != 0) System.arraycopy(bpacket, 0, fullPacket, packetPrefix.length, bpacket.length);
|
||||||
|
for (WebSocket pl : Main.clients.keySet()) {
|
||||||
|
if (pl.equals(conn)) continue;
|
||||||
|
if (pl.isOpen()) pl.send(fullPacket);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}catch(Throwable t) {
|
||||||
|
// hacker
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeSkin(String username) {
|
||||||
|
skinCollection.remove(username);
|
||||||
|
capeCollection.remove(username);
|
||||||
|
lastSkinLayerUpdate.remove(username);
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,6 +63,7 @@ public class WebSocketProxy extends WebSocketServer {
|
||||||
Client selfClient = Main.clients.remove(conn);
|
Client selfClient = Main.clients.remove(conn);
|
||||||
if (selfClient != null) {
|
if (selfClient != null) {
|
||||||
System.out.println("Player " + selfClient.username + " (" + Main.getIp(conn) + ") left!");
|
System.out.println("Player " + selfClient.username + " (" + Main.getIp(conn) + ") left!");
|
||||||
|
Skins.removeSkin(selfClient.username);
|
||||||
if (selfClient.socket.isClosed()) {
|
if (selfClient.socket.isClosed()) {
|
||||||
try {
|
try {
|
||||||
selfClient.socket.close();
|
selfClient.socket.close();
|
||||||
|
@ -88,7 +89,7 @@ public class WebSocketProxy extends WebSocketServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(WebSocket conn, ByteBuffer message) {
|
public void onMessage(WebSocket conn, ByteBuffer message) { // todo: make use of the fact that it's already a bytebuffer dumbass
|
||||||
if (Main.bans.contains(Main.getIp(conn))) {
|
if (Main.bans.contains(Main.getIp(conn))) {
|
||||||
conn.close();
|
conn.close();
|
||||||
return;
|
return;
|
||||||
|
@ -97,60 +98,132 @@ public class WebSocketProxy extends WebSocketServer {
|
||||||
byte[] msg = message.array();
|
byte[] msg = message.array();
|
||||||
if (!Main.clients.containsKey(conn)) {
|
if (!Main.clients.containsKey(conn)) {
|
||||||
if (msg.length > 3 && msg[1] == (byte) 69) {
|
if (msg.length > 3 && msg[1] == (byte) 69) {
|
||||||
if (msg[3] < 3 || msg[3] > 16) {
|
// todo: it uses shorts dumbass, get with the system
|
||||||
|
short unameLen = (short) ((msg[2] << 8) + msg[3] & 0xff);
|
||||||
|
if (unameLen < 3 || unameLen > 16) {
|
||||||
conn.close();
|
conn.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
byte[] uname = new byte[msg[3]];
|
|
||||||
if (msg.length < 5 + msg[3] * 2) {
|
if (msg.length < 5 + msg[3] * 2) {
|
||||||
conn.close();
|
conn.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
byte[] uname = new byte[unameLen];
|
||||||
for (int i = 0; i < uname.length; i++) uname[i] = msg[5 + i * 2];
|
for (int i = 0; i < uname.length; i++) uname[i] = msg[5 + i * 2];
|
||||||
String username = new String(uname);
|
String username = new String(uname);
|
||||||
Main.clients.put(conn, new Client(username));
|
Client selfClient = new Client(username);
|
||||||
|
Main.clients.put(conn, selfClient);
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Socket selfSocket = new Socket(Main.hostname, Main.port);
|
boolean firstTime = true;
|
||||||
Client selfClient = Main.clients.get(conn);
|
while (conn.isOpen()) {
|
||||||
selfClient.setSocket(selfSocket);
|
int currServer = selfClient.server;
|
||||||
while (selfClient.msgCache.size() > 0) selfClient.socketOut.write(selfClient.msgCache.remove(0));
|
ServerItem chosenServer = Main.servers.get(currServer);
|
||||||
while (conn.isOpen() && !selfSocket.isInputShutdown()) {
|
Socket selfSocket = new Socket(chosenServer.host, chosenServer.port);
|
||||||
byte[] data = new byte[maxBuffSize];
|
selfClient.setSocket(selfSocket);
|
||||||
int read = selfClient.socketIn.read(data, 0, maxBuffSize);
|
if (!firstTime) sendToServer(selfClient.handshake, selfClient);
|
||||||
if (read == maxBuffSize) {
|
while (selfClient.msgCache.size() > 0) sendToServer(selfClient.msgCache.remove(0), selfClient);
|
||||||
|
while (conn.isOpen() && !selfSocket.isInputShutdown() && selfClient.server == currServer) {
|
||||||
|
byte[] dataa = new byte[maxBuffSize];
|
||||||
|
int read = selfClient.socketIn.read(dataa, 0, maxBuffSize);
|
||||||
|
byte[] data;
|
||||||
|
if (read == maxBuffSize) {
|
||||||
|
data = dataa;
|
||||||
|
} else if (read > 0) {
|
||||||
|
data = new byte[read];
|
||||||
|
System.arraycopy(dataa, 0, data, 0, read);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (firstTime && data[0] == 1) selfClient.clientEntityId = selfClient.serverEntityId = EntityMap.readInt(data, 1);
|
||||||
|
if (!firstTime && data[0] == 1) {
|
||||||
|
selfClient.serverEntityId = EntityMap.readInt(data, 1);
|
||||||
|
// assume server is giving valid data; we don't have to validate it because it isn't a potentially malicious client
|
||||||
|
byte[] worldByte = new byte[data[6] * 2 + 2];
|
||||||
|
System.arraycopy(data, 5, worldByte, 0, worldByte.length);
|
||||||
|
byte gamemode = data[worldByte.length + 5];
|
||||||
|
byte dimension = data[worldByte.length + 6];
|
||||||
|
byte difficulty = data[worldByte.length + 7];
|
||||||
|
Arrays.fill(data, (byte) 0);
|
||||||
|
data[0] = 9;
|
||||||
|
EntityMap.setInt(data, 1, dimension);
|
||||||
|
data[5] = difficulty;
|
||||||
|
data[6] = gamemode;
|
||||||
|
data[7] = (byte)(256 & 0xff);
|
||||||
|
data[8] = (byte)((256 >> 8) & 0xff);
|
||||||
|
System.arraycopy(worldByte, 0, data, 9, worldByte.length);
|
||||||
|
read = 9 + worldByte.length;
|
||||||
|
byte[] trimData = new byte[read];
|
||||||
|
System.arraycopy(data, 0, trimData, 0, read);
|
||||||
|
data = trimData;
|
||||||
|
if (conn.isOpen()) conn.send(new byte[] { 9, 0, 0, 0, 1, 0, 0, 1, 0, 0, 7, 0, 100, 0, 101, 0, 102, 0, 97, 0, 117, 0, 108, 0, 116 });
|
||||||
|
if (conn.isOpen()) conn.send(new byte[] { 9, 0, 0, 0, -1, 0, 0, 1, 0, 0, 7, 0, 100, 0, 101, 0, 102, 0, 97, 0, 117, 0, 108, 0, 116 });
|
||||||
|
}
|
||||||
|
EntityMap.rewrite(data, selfClient.serverEntityId, selfClient.clientEntityId);
|
||||||
if (conn.isOpen()) conn.send(data);
|
if (conn.isOpen()) conn.send(data);
|
||||||
} else if (read > 0) {
|
|
||||||
byte[] trueData = new byte[read];
|
|
||||||
System.arraycopy(data, 0, trueData, 0, read);
|
|
||||||
if (conn.isOpen()) conn.send(trueData);
|
|
||||||
}
|
}
|
||||||
|
if (conn.isOpen() && selfClient.server == currServer) conn.close();
|
||||||
|
if (!selfSocket.isClosed()) selfSocket.close();
|
||||||
|
selfClient.socketOut = null;
|
||||||
|
firstTime = false;
|
||||||
}
|
}
|
||||||
if (conn.isOpen()) conn.close();
|
|
||||||
if (!selfSocket.isClosed()) selfSocket.close();
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
conn.close();
|
conn.close();
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
msg[1] = (byte) 61;
|
msg[1] = (byte) 61;
|
||||||
|
selfClient.handshake = msg;
|
||||||
System.out.println("Player " + username + " (" + Main.getIp(conn) + ") joined!");
|
System.out.println("Player " + username + " (" + Main.getIp(conn) + ") joined!");
|
||||||
} else {
|
} else {
|
||||||
conn.close();
|
conn.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byte[] packet = message.array();
|
|
||||||
if (!Main.eaglerPackets && packet.length >= 11 && packet[0] == -6 && packet[2] >= 4 && packet[4] == 69 && packet[6] == 65 && packet[8] == 71 && packet[10] == 124) return; // EAG|
|
|
||||||
Client currClient = Main.clients.get(conn);
|
Client currClient = Main.clients.get(conn);
|
||||||
if (currClient.socketOut == null) {
|
if (msg.length >= 3 && msg[0] == 3) {
|
||||||
currClient.msgCache.add(packet);
|
int msgLen = (short) ((msg[1] << 8) + msg[2] & 0xff);
|
||||||
} else if (!currClient.socket.isOutputShutdown()) {
|
if (msgLen != 0) {
|
||||||
|
if (msg.length >= 3 + msgLen * 2) {
|
||||||
|
byte[] chatBytes = new byte[msgLen];
|
||||||
|
for (int i = 0; i < chatBytes.length; i++) chatBytes[i] = msg[4 + i * 2];
|
||||||
|
String chatMsg = new String(chatBytes);
|
||||||
|
if (chatMsg.toLowerCase().startsWith("/server")) {
|
||||||
|
String msgArgs = chatMsg.substring(7 + (chatMsg.contains(" ") ? 1 : 0));
|
||||||
|
if (msgArgs.isEmpty()) {
|
||||||
|
//usage msg
|
||||||
|
conn.send(new byte[] { 3, 0, 25, 0, (byte) 167, 0, 57, 0, 85, 0, 115, 0, 97, 0, 103, 0, 101, 0, 58, 0, 32, 0, 47, 0, 115, 0, 101, 0, 114, 0, 118, 0, 101, 0, 114, 0, 32, 0, 60, 0, 110, 0, 117, 0, 109, 0, 98, 0, 101, 0, 114, 0, 62 });
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
int destServer = Integer.parseInt(msgArgs);
|
||||||
|
currClient.server = Math.max(0, Math.min(Main.servers.size() - 1, destServer));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
//not a number
|
||||||
|
conn.send(new byte[] { 3, 0, 29, 0, (byte) 167, 0, 57, 0, 84, 0, 104, 0, 97, 0, 116, 0, 32, 0, 105, 0, 115, 0, 32, 0, 110, 0, 111, 0, 116, 0, 32, 0, 97, 0, 32, 0, 118, 0, 97, 0, 108, 0, 105, 0, 100, 0, 32, 0, 110, 0, 117, 0, 109, 0, 98, 0, 101, 0, 114, 0, 33 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return; // don't send to underlying server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msg.length > 0 && msg[0] == (byte) 250) {
|
||||||
|
if (Skins.setSkin(currClient.username, conn, msg)) return;
|
||||||
|
}
|
||||||
|
if (currClient.socketOut == null || currClient.socket.isOutputShutdown()) {
|
||||||
|
currClient.msgCache.add(msg);
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
currClient.socketOut.write(packet);
|
sendToServer(msg, currClient);
|
||||||
} catch (IOException ignored) {}
|
} catch (IOException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendToServer(byte[] orig, Client client) throws IOException {
|
||||||
|
byte[] data = orig.clone();
|
||||||
|
EntityMap.rewrite(data, client.clientEntityId, client.serverEntityId);
|
||||||
|
client.socketOut.write(data);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(WebSocket conn, Exception ex) {
|
public void onError(WebSocket conn, Exception ex) {
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
# mc server ip
|
# mc servers in network. first one is default/hub
|
||||||
hostname: localhost
|
servers:
|
||||||
# mc server port
|
- localhost:25569
|
||||||
port: 25569
|
|
||||||
# ayungee port
|
# ayungee port
|
||||||
web_port: 25565
|
web_port: 25565
|
||||||
# if this is behind a reverse proxy, such as caddy or nginx. uses X-Real-IP header.
|
# if this is behind a reverse proxy, such as caddy or nginx. uses X-Real-IP header.
|
||||||
forwarded: false
|
forwarded: false
|
||||||
# forward eagler-specific packets?
|
|
||||||
eag_packets: false
|
|
||||||
# origin blacklist URL (leave empty to disable syncing)
|
# origin blacklist URL (leave empty to disable syncing)
|
||||||
origin_blacklist: "https://g.eags.us/eaglercraft/origin_blacklist.txt"
|
origin_blacklist: "https://g.eags.us/eaglercraft/origin_blacklist.txt"
|
||||||
# whitelisted origins -- if specified, only allows the listed origins to connect
|
# whitelisted origins -- if specified, only allows the listed origins to connect
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user