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")