From 26e0436b91a6a6bd6d8352b1c5fc2ea6ebc939a9 Mon Sep 17 00:00:00 2001 From: Dereku Date: Mon, 18 Nov 2024 21:40:27 +0700 Subject: [PATCH] 25565 mirror port --- pom.xml | 2 +- .../legacyping/CrutchBukkitMirrorThread.java | 106 ++++++++++++++++++ .../net/rubeta/legacyping/LegacyPing.java | 12 +- .../net/rubeta/legacyping/ServerThread.java | 2 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java diff --git a/pom.xml b/pom.xml index 1ef3156..e4be042 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.8 + 2.0 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java b/src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java new file mode 100644 index 0000000..b422206 --- /dev/null +++ b/src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java @@ -0,0 +1,106 @@ +package net.rubeta.legacyping; + +import net.minecraft.network.packets.Packet; +import net.minecraft.network.packets.Packet255KickDisconnect; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.server.ServerListPingEvent; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class CrutchBukkitMirrorThread extends Thread { + + private final AtomicBoolean working = new AtomicBoolean(false); + private final Logger logger; + private ServerSocket serverSocket; + private final InetAddress address; + private final LegacyPing plugin; + + public CrutchBukkitMirrorThread(final LegacyPing plugin) { + this.plugin = plugin; + this.logger = Logger.getLogger("mirror:25565"); + + try { + this.address = InetAddress.getByName("0.0.0.0"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + + @Override + public void run() { + this.working.set(true); + while (this.working.get()) { + try { + this.serverSocket = new ServerSocket(25565, 10, address); + this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); + this.serverSocket.setPerformancePreferences(0, 2, 1); + } catch (IOException e) { + this.logger.log(Level.WARNING, "Failed to start ServerSocket", e); + this.pause(); + continue; + } + + while (!this.serverSocket.isClosed()) { + if (!this.working.get()) { + break; + } + + InetAddress address = null; + try (final Socket socket = this.serverSocket.accept()) { + final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); + final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); + address = socket.getInetAddress(); + socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); + inputStream.readInt(); // Packet length + Packet packet = Packet.readPacket(inputStream); + if (packet != null && packet.getPacketId() == 254) { + CraftServer server = (CraftServer) this.plugin.getServer(); + ServerListPingEvent pingEvent = CraftEventFactory.callServerListPingEvent( + server, address, server.getServer().motd, + server.getOnlinePlayers().length, server.getMaxPlayers() + ); + String s = pingEvent.getMotd() + "\u0000" + server.getOnlinePlayers().length + "\u0000" + pingEvent.getMaxPlayers(); + Packet255KickDisconnect response = new Packet255KickDisconnect(s); + outputStream.writeInt(s.length() + 1); + outputStream.writeByte(255); + response.writePacketData(outputStream); + } + } catch (SocketTimeoutException | EOFException ignore) { + } catch (Exception ex) { + this.logger.warning("An exception occurred while communicating with " + address); + this.logger.log(Level.WARNING, "Exception in " + this.getName(), ex); + } + } + } + } + + + public void shutdown() { + this.working.set(false); + try { + this.serverSocket.close(); + } catch (IOException ignore) { + } + } + + + void pause() { + this.pause(TimeUnit.SECONDS.toMillis(30L)); + } + + void pause(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ignored) { + } + } +} diff --git a/src/main/java/net/rubeta/legacyping/LegacyPing.java b/src/main/java/net/rubeta/legacyping/LegacyPing.java index 5f17d66..050d286 100644 --- a/src/main/java/net/rubeta/legacyping/LegacyPing.java +++ b/src/main/java/net/rubeta/legacyping/LegacyPing.java @@ -13,6 +13,7 @@ import java.util.logging.Level; public final class LegacyPing extends JavaPlugin { private final List threads = new ArrayList<>(); + private CrutchBukkitMirrorThread mirror = null; @Override public void onEnable() { @@ -33,11 +34,18 @@ public final class LegacyPing extends JavaPlugin { this.getLogger().log(Level.WARNING, "Failed to create ServerSocket", e); } } + if (config.getBoolean("enableMirrorPort", false)) { + this.mirror = new CrutchBukkitMirrorThread(this); + this.mirror.start(); + } this.threads.forEach(Thread::start); } @Override public void onDisable() { + if (this.mirror != null) { + this.mirror.shutdown(); + } this.threads.forEach(ServerThread::shutdown); } @@ -46,7 +54,9 @@ public final class LegacyPing extends JavaPlugin { if (!sender.isOp()) { return true; } - + if (this.mirror != null) { + this.mirror.shutdown(); + } this.threads.forEach(ServerThread::shutdown); this.threads.clear(); this.startThreads(); diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index fdfb5a2..cfeea8f 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -50,7 +50,7 @@ public class ServerThread extends Thread { } public static void main(String[] args) throws IOException { - new ServerThread("", 25565).start(); + new ServerThread("", 25569).start(); } @SuppressWarnings("unused")