From bb593022fce1020099405f57c50f010d7565654b Mon Sep 17 00:00:00 2001
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
Date: Sun, 17 Mar 2019 21:46:56 +0200
Subject: [PATCH] Fire event on GS4 query


diff --git a/src/main/java/net/minecraft/server/RemoteConnectionThread.java b/src/main/java/net/minecraft/server/RemoteConnectionThread.java
index 66bfbcf02b..d821ef9a75 100644
--- a/src/main/java/net/minecraft/server/RemoteConnectionThread.java
+++ b/src/main/java/net/minecraft/server/RemoteConnectionThread.java
@@ -15,7 +15,7 @@ public abstract class RemoteConnectionThread implements Runnable {
     private static final Logger LOGGER = LogManager.getLogger();
     private static final AtomicInteger i = new AtomicInteger(0);
     protected boolean a;
-    protected final IMinecraftServer b;
+    protected final IMinecraftServer b; protected IMinecraftServer getServer() { return this.b; } // Paper - OBFHELPER
     protected final String c;
     protected Thread d;
     protected final int e = 5;
@@ -94,6 +94,7 @@ public abstract class RemoteConnectionThread implements Runnable {
         this.b.g(s);
     }
 
+    protected int getPlayerCount() { return this.d(); } // Paper - OBFHELPER
     protected int d() {
         return this.b.getPlayerCount();
     }
diff --git a/src/main/java/net/minecraft/server/RemoteStatusListener.java b/src/main/java/net/minecraft/server/RemoteStatusListener.java
index ddb4ba4899..3770334fc4 100644
--- a/src/main/java/net/minecraft/server/RemoteStatusListener.java
+++ b/src/main/java/net/minecraft/server/RemoteStatusListener.java
@@ -21,19 +21,19 @@ public class RemoteStatusListener extends RemoteConnectionThread {
 
     private long h;
     private final int i;
-    private final int j;
-    private final int k;
-    private final String l;
-    private final String m;
+    private final int j; private int getServerPort() { return this.j; } // Paper - OBFHELPER
+    private final int k; private int getMaxPlayers() { return this.k; } // Paper - OBFHELPER
+    private final String l; private String getMotd() { return this.l; } // Paper - OBFHELPER
+    private final String m; private String getWorldName() { return this.m; } // Paper - OBFHELPER
     private DatagramSocket n;
     private final byte[] o = new byte[1460];
     private DatagramPacket p;
     private final Map<SocketAddress, String> q;
-    private String r;
+    private String r; private String getServerHost() { return this.r; } // Paper - OBFHELPER
     private String s;
     private final Map<SocketAddress, RemoteStatusListener.RemoteStatusChallenge> t;
     private final long u;
-    private final RemoteStatusReply v;
+    private final RemoteStatusReply v; private RemoteStatusReply getCachedFullResponse() { return this.v; } // Paper - OBFHELPER
     private long w;
 
     public RemoteStatusListener(IMinecraftServer iminecraftserver) {
@@ -91,6 +91,7 @@ public class RemoteStatusListener extends RemoteConnectionThread {
 
                     remotestatusreply.a((int) 0);
                     remotestatusreply.a(this.a(datagrampacket.getSocketAddress()));
+                    /* Paper start - GS4 Query event
                     remotestatusreply.a(this.l);
                     remotestatusreply.a("SMP");
                     remotestatusreply.a(this.m);
@@ -98,6 +99,31 @@ public class RemoteStatusListener extends RemoteConnectionThread {
                     remotestatusreply.a(Integer.toString(this.k));
                     remotestatusreply.a((short) this.j);
                     remotestatusreply.a(this.r);
+                    */
+                    com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
+                        com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC;
+                    com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
+                        .motd(this.getMotd())
+                        .map(this.getWorldName())
+                        .currentPlayers(this.getPlayerCount())
+                        .maxPlayers(this.getMaxPlayers())
+                        .port(this.getServerPort())
+                        .hostname(this.getServerHost())
+                        .gameVersion(this.getServer().getVersion())
+                        .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
+                        .build();
+                    com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
+                        new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, datagrampacket.getAddress(), queryResponse);
+                    queryEvent.callEvent();
+                    queryResponse = queryEvent.getResponse();
+                    remotestatusreply.writeString(queryResponse.getMotd());
+                    remotestatusreply.writeString("SMP");
+                    remotestatusreply.writeString(queryResponse.getMap());
+                    remotestatusreply.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
+                    remotestatusreply.writeString(Integer.toString(queryResponse.getMaxPlayers()));
+                    remotestatusreply.writeShort((short) queryResponse.getPort());
+                    remotestatusreply.writeString(queryResponse.getHostname());
+                    // Paper end
                     this.a(remotestatusreply.a(), datagrampacket);
                     this.a("Status [" + socketaddress + "]");
                 }
@@ -134,6 +160,7 @@ public class RemoteStatusListener extends RemoteConnectionThread {
             this.v.a("splitnum");
             this.v.a((int) 128);
             this.v.a((int) 0);
+            /* Paper start - GS4 Query event
             this.v.a("hostname");
             this.v.a(this.l);
             this.v.a("gametype");
@@ -169,6 +196,79 @@ public class RemoteStatusListener extends RemoteConnectionThread {
             }
 
             this.v.a((int) 0);
+            */
+            // Pack plugins
+            java.util.List<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> plugins = java.util.Collections.emptyList();
+            org.bukkit.plugin.Plugin[] bukkitPlugins;
+            if(((DedicatedServer) this.getServer()).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) {
+                plugins = java.util.stream.Stream.of(bukkitPlugins)
+                    .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion()))
+                    .collect(java.util.stream.Collectors.toList());
+            }
+
+            com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
+                .motd(this.getMotd())
+                .map(this.getWorldName())
+                .currentPlayers(this.getPlayerCount())
+                .maxPlayers(this.getMaxPlayers())
+                .port(this.getServerPort())
+                .hostname(this.getServerHost())
+                .plugins(plugins)
+                .players(this.getServer().getPlayers())
+                .gameVersion(this.getServer().getVersion())
+                .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
+                .build();
+            com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
+                com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL;
+            com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
+                new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, datagrampacket.getAddress(), queryResponse);
+            queryEvent.callEvent();
+            queryResponse = queryEvent.getResponse();
+            this.getCachedFullResponse().writeString("hostname");
+            this.getCachedFullResponse().writeString(queryResponse.getMotd());
+            this.getCachedFullResponse().writeString("gametype");
+            this.getCachedFullResponse().writeString("SMP");
+            this.getCachedFullResponse().writeString("game_id");
+            this.getCachedFullResponse().writeString("MINECRAFT");
+            this.getCachedFullResponse().writeString("version");
+            this.getCachedFullResponse().writeString(queryResponse.getGameVersion());
+            this.getCachedFullResponse().writeString("plugins");
+            java.lang.StringBuilder pluginsString = new java.lang.StringBuilder();
+            pluginsString.append(queryResponse.getServerVersion());
+            if(!queryResponse.getPlugins().isEmpty()) {
+                pluginsString.append(": ");
+                Iterator<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> iter = queryResponse.getPlugins().iterator();
+                while(iter.hasNext()) {
+                    com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next();
+                    pluginsString.append(info.getName());
+                    if (info.getVersion() != null) {
+                        pluginsString.append(' ').append(info.getVersion().replaceAll(";", ","));
+                    }
+                    if (iter.hasNext()) {
+                        pluginsString.append(';').append(' ');
+                    }
+                }
+            }
+            this.getCachedFullResponse().writeString(pluginsString.toString());
+            this.getCachedFullResponse().writeString("map");
+            this.getCachedFullResponse().writeString(queryResponse.getMap());
+            this.getCachedFullResponse().writeString("numplayers");
+            this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getCurrentPlayers()));
+            this.getCachedFullResponse().writeString("maxplayers");
+            this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getMaxPlayers()));
+            this.getCachedFullResponse().writeString("hostport");
+            this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getPort()));
+            this.getCachedFullResponse().writeString("hostip");
+            this.getCachedFullResponse().writeString(queryResponse.getHostname());
+            // The "meaningless data" start, copied from above
+            this.getCachedFullResponse().writeInt(0);
+            this.getCachedFullResponse().writeInt(1);
+            this.getCachedFullResponse().writeString("player_");
+            this.getCachedFullResponse().writeInt(0);
+            // "Meaningless data" end
+            queryResponse.getPlayers().forEach(this.getCachedFullResponse()::writeStringUnchecked);
+            this.getCachedFullResponse().writeInt(0);
+            // Paper end
             return this.v.a();
         }
     }
diff --git a/src/main/java/net/minecraft/server/RemoteStatusReply.java b/src/main/java/net/minecraft/server/RemoteStatusReply.java
index 848b5c3f0e..73efea7e13 100644
--- a/src/main/java/net/minecraft/server/RemoteStatusReply.java
+++ b/src/main/java/net/minecraft/server/RemoteStatusReply.java
@@ -18,15 +18,27 @@ public class RemoteStatusReply {
         this.b.write(abyte, 0, abyte.length);
     }
 
+    public void writeString(String string) throws IOException { this.a(string); } // Paper - OBFHELPER
     public void a(String s) throws IOException {
         this.b.writeBytes(s);
         this.b.write(0);
     }
+    // Paper start - unchecked exception variant to use in Stream API
+    public void writeStringUnchecked(String string) {
+        try {
+            writeString(string);
+        } catch (IOException e) {
+            com.destroystokyo.paper.util.SneakyThrow.sneaky(e);
+        }
+    }
+    // Paper end
 
+    public void writeInt(int i) throws IOException { this.a(i); } // Paper - OBFHELPER
     public void a(int i) throws IOException {
         this.b.write(i);
     }
 
+    public void writeShort(short i) throws IOException { this.a(i); } // Paper - OBFHELPER
     public void a(short short0) throws IOException {
         this.b.writeShort(Short.reverseBytes(short0));
     }
-- 
2.21.0