diff --git a/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java b/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java
new file mode 100644
index 000000000..9886e1f75
--- /dev/null
+++ b/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java
@@ -0,0 +1,27 @@
+package net.minestom.server.extras.bungee;
+
+/**
+ * BungeeCord forwarding support. This does not count as a security feature and you will still be required to manage your firewall.
+ *
+ * Please consider using {@link net.minestom.server.extras.velocity.VelocityProxy} instead.
+ */
+public final class BungeeCordProxy {
+
+ private static boolean enabled;
+
+ /**
+ * Enables bungee IP forwarding.
+ */
+ public static void enable() {
+ BungeeCordProxy.enabled = true;
+ }
+
+ /**
+ * Gets if bungee IP forwarding is enabled.
+ *
+ * @return true if forwarding is enabled
+ */
+ public static boolean isEnabled() {
+ return enabled;
+ }
+}
diff --git a/src/main/java/net/minestom/server/network/PacketProcessor.java b/src/main/java/net/minestom/server/network/PacketProcessor.java
index df8d60e9b..77d4d6556 100644
--- a/src/main/java/net/minestom/server/network/PacketProcessor.java
+++ b/src/main/java/net/minestom/server/network/PacketProcessor.java
@@ -14,13 +14,19 @@ import net.minestom.server.network.packet.client.handshake.HandshakePacket;
import net.minestom.server.network.player.NettyPlayerConnection;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.binary.BinaryReader;
+import net.minestom.server.utils.binary.Readable;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class PacketProcessor {
+ private final static Logger LOGGER = LoggerFactory.getLogger(PacketProcessor.class);
+
private final Map connectionPlayerConnectionMap = new ConcurrentHashMap<>();
// Protocols state
@@ -34,7 +40,7 @@ public final class PacketProcessor {
this.playPacketsHandler = new ClientPlayPacketsHandler();
}
- public void process(ChannelHandlerContext channel, InboundPacket packet) {
+ public void process(@NotNull ChannelHandlerContext channel, @NotNull InboundPacket packet) {
// Create the netty player connection object if not existing
PlayerConnection playerConnection = connectionPlayerConnectionMap.computeIfAbsent(
channel, c -> new NettyPlayerConnection((SocketChannel) channel.channel())
@@ -51,7 +57,7 @@ public final class PacketProcessor {
// Should be handshake packet
if (packet.packetId == 0) {
HandshakePacket handshakePacket = new HandshakePacket();
- handshakePacket.read(binaryReader);
+ safeRead(playerConnection, handshakePacket, binaryReader);
handshakePacket.process(playerConnection);
}
return;
@@ -61,17 +67,17 @@ public final class PacketProcessor {
case PLAY:
final Player player = playerConnection.getPlayer();
ClientPlayPacket playPacket = (ClientPlayPacket) playPacketsHandler.getPacketInstance(packet.packetId);
- playPacket.read(binaryReader);
+ safeRead(playerConnection, playPacket, binaryReader);
player.addPacketToQueue(playPacket);
break;
case LOGIN:
final ClientPreplayPacket loginPacket = (ClientPreplayPacket) loginPacketsHandler.getPacketInstance(packet.packetId);
- loginPacket.read(binaryReader);
+ safeRead(playerConnection, loginPacket, binaryReader);
loginPacket.process(playerConnection);
break;
case STATUS:
final ClientPreplayPacket statusPacket = (ClientPreplayPacket) statusPacketsHandler.getPacketInstance(packet.packetId);
- statusPacket.read(binaryReader);
+ safeRead(playerConnection, statusPacket, binaryReader);
statusPacket.process(playerConnection);
break;
}
@@ -91,4 +97,14 @@ public final class PacketProcessor {
public void removePlayerConnection(ChannelHandlerContext channel) {
connectionPlayerConnectionMap.remove(channel);
}
+
+ private void safeRead(@NotNull PlayerConnection connection, @NotNull Readable readable, @NotNull BinaryReader reader) {
+ try {
+ readable.read(reader);
+ } catch (Exception e) {
+ final Player player = connection.getPlayer();
+ final String username = player != null ? player.getUsername() : "null";
+ LOGGER.warn("Connection " + connection.getRemoteAddress() + " (" + username + ") sent an unexpected packet.");
+ }
+ }
}
diff --git a/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java b/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java
index 9658a9af1..8ccff15cd 100644
--- a/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java
+++ b/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java
@@ -3,6 +3,7 @@ package net.minestom.server.network.packet.client.handshake;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
+import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
@@ -11,6 +12,8 @@ import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.binary.BinaryReader;
import org.jetbrains.annotations.NotNull;
+import java.net.SocketAddress;
+
public class HandshakePacket implements ClientPreplayPacket {
/**
@@ -18,6 +21,8 @@ public class HandshakePacket implements ClientPreplayPacket {
*/
private static final ColoredText INVALID_VERSION_TEXT = ColoredText.of(ChatColor.RED, "Invalid Version, please use " + MinecraftServer.VERSION_NAME);
+ private static final ColoredText INVALID_BUNGEE_FORWARDING = ColoredText.of(ChatColor.RED, "If you wish to use IP forwarding, please enable it in your BungeeCord config as well!");
+
private int protocolVersion;
private String serverAddress;
private int serverPort;
@@ -33,6 +38,29 @@ public class HandshakePacket implements ClientPreplayPacket {
@Override
public void process(@NotNull PlayerConnection connection) {
+
+ if (BungeeCordProxy.isEnabled() && connection instanceof NettyPlayerConnection) {
+ NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection;
+
+ if (serverAddress != null) {
+ final String[] split = serverAddress.split("\00");
+
+ if (split.length == 3 || split.length == 4) {
+ this.serverAddress = split[0];
+
+ final SocketAddress socketAddress = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort());
+ nettyPlayerConnection.setRemoteAddress(socketAddress);
+ } else {
+ nettyPlayerConnection.sendPacket(new LoginDisconnectPacket(INVALID_BUNGEE_FORWARDING));
+ nettyPlayerConnection.disconnect();
+ return;
+ }
+ } else {
+ // Happen when a client ping the server, ignore
+ return;
+ }
+ }
+
switch (nextState) {
case 1:
connection.setConnectionState(ConnectionState.STATUS);
diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java
index 9b106397a..1891e5b6e 100644
--- a/src/test/java/demo/Main.java
+++ b/src/test/java/demo/Main.java
@@ -7,6 +7,7 @@ import demo.commands.GamemodeCommand;
import demo.commands.TestCommand;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager;
+import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
import net.minestom.server.storage.StorageManager;
@@ -51,8 +52,9 @@ public class Main {
PlayerInit.init();
//VelocityProxy.enable("rBeJJ79W4MVU");
+ BungeeCordProxy.enable();
- //MojangAuth.init();
+ // MojangAuth.init();
minecraftServer.start("0.0.0.0", 25565, PlayerInit.getResponseDataConsumer());
}
diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java
index 2dfa2c6e7..4705aecbd 100644
--- a/src/test/java/demo/PlayerInit.java
+++ b/src/test/java/demo/PlayerInit.java
@@ -5,8 +5,6 @@ import demo.generator.NoiseTestGenerator;
import net.minestom.server.MinecraftServer;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.chat.ColoredText;
-import net.minestom.server.data.Data;
-import net.minestom.server.data.NbtDataImpl;
import net.minestom.server.entity.*;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.type.monster.EntityZombie;
@@ -174,11 +172,7 @@ public class PlayerInit {
}
ItemStack itemStack = new ItemStack(Material.DIAMOND_PICKAXE, (byte) 64);
- Data data = new NbtDataImpl();
- data.set("test", 51);
- itemStack.setData(data);
player.getInventory().addItemStack(itemStack);
- System.out.println("test " + data.get("test"));
//player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte)64));
});
diff --git a/src/test/java/demo/commands/TestCommand.java b/src/test/java/demo/commands/TestCommand.java
index 456458317..83a5abd57 100644
--- a/src/test/java/demo/commands/TestCommand.java
+++ b/src/test/java/demo/commands/TestCommand.java
@@ -5,6 +5,7 @@ import net.minestom.server.command.builder.Arguments;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
+import net.minestom.server.item.ItemStack;
public class TestCommand extends Command {
@@ -17,7 +18,7 @@ public class TestCommand extends Command {
//addSyntax(this::execute, dynamicWord);
}
- Argument test = ArgumentType.DynamicWord("testArg").fromRestrictions(value -> value.contains("a"));
+ Argument test = ArgumentType.ItemStack("item");
test.setCallback((source, value, error) -> {
System.out.println("ERROR " + error);
@@ -29,7 +30,8 @@ public class TestCommand extends Command {
});
addSyntax((source, args) -> {
- System.out.println("HEY IT WORKS");
+ ItemStack itemStack = args.getItemStack("item");
+ System.out.println("HEY IT WORKS "+itemStack.getMaterial());
}, test);
}