From 0000000000000000000000000000000000000000 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/rcon/NetworkDataOutputStream.java b/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java
index 51cb2644aa516a59e19fecb308d519dbc7e5fb11..e548aa0ca4e1e94ab628614b44fc11568ca3beff 100644
--- a/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java
+++ b/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java
@@ -22,6 +22,16 @@ public class NetworkDataOutputStream {
         this.dataOutputStream.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 write(int value) throws IOException {
         this.dataOutputStream.write(value);
     }
diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
index 88917d7a179739fc13c59831b15e7ddc711bed1b..1ef089dbf83de35d875c00efdf468c397be56978 100644
--- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
+++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
@@ -106,13 +106,32 @@ public class QueryThreadGs4 extends GenericThread {
                         NetworkDataOutputStream networkDataOutputStream = new NetworkDataOutputStream(1460);
                         networkDataOutputStream.write(0);
                         networkDataOutputStream.writeBytes(this.getIdentBytes(packet.getSocketAddress()));
-                        networkDataOutputStream.writeString(this.serverName);
+
+                        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.serverName)
+                            .map(this.worldName)
+                            .currentPlayers(this.serverInterface.getPlayerCount())
+                            .maxPlayers(this.maxPlayers)
+                            .port(this.serverPort)
+                            .hostname(this.hostIp)
+                            .gameVersion(this.serverInterface.getServerVersion())
+                            .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, packet.getAddress(), queryResponse);
+                        queryEvent.callEvent();
+                        queryResponse = queryEvent.getResponse();
+
+                        networkDataOutputStream.writeString(queryResponse.getMotd());
                         networkDataOutputStream.writeString("SMP");
-                        networkDataOutputStream.writeString(this.worldName);
-                        networkDataOutputStream.writeString(Integer.toString(this.serverInterface.getPlayerCount()));
-                        networkDataOutputStream.writeString(Integer.toString(this.maxPlayers));
-                        networkDataOutputStream.writeShort((short)this.serverPort);
-                        networkDataOutputStream.writeString(this.hostIp);
+                        networkDataOutputStream.writeString(queryResponse.getMap());
+                        networkDataOutputStream.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
+                        networkDataOutputStream.writeString(Integer.toString(queryResponse.getMaxPlayers()));
+                        networkDataOutputStream.writeShort((short) queryResponse.getPort());
+                        networkDataOutputStream.writeString(queryResponse.getHostname());
+                        // Paper end
                         this.sendTo(networkDataOutputStream.toByteArray(), packet);
                         LOGGER.debug("Status [{}]", (Object)socketAddress);
                     }
@@ -147,31 +166,75 @@ public class QueryThreadGs4 extends GenericThread {
             this.rulesResponse.writeString("splitnum");
             this.rulesResponse.write(128);
             this.rulesResponse.write(0);
+            // Paper start
+            // Pack plugins
+            java.util.List<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> plugins = java.util.Collections.emptyList();
+            org.bukkit.plugin.Plugin[] bukkitPlugins;
+            if (((net.minecraft.server.dedicated.DedicatedServer) this.serverInterface).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.serverName)
+                .map(this.worldName)
+                .currentPlayers(this.serverInterface.getPlayerCount())
+                .maxPlayers(this.maxPlayers)
+                .port(this.serverPort)
+                .hostname(this.hostIp)
+                .plugins(plugins)
+                .players(this.serverInterface.getPlayerNames())
+                .gameVersion(this.serverInterface.getServerVersion())
+                .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, packet.getAddress(), queryResponse);
+            queryEvent.callEvent();
+            queryResponse = queryEvent.getResponse();
             this.rulesResponse.writeString("hostname");
-            this.rulesResponse.writeString(this.serverName);
+            this.rulesResponse.writeString(queryResponse.getMotd());
             this.rulesResponse.writeString("gametype");
             this.rulesResponse.writeString("SMP");
             this.rulesResponse.writeString("game_id");
             this.rulesResponse.writeString("MINECRAFT");
             this.rulesResponse.writeString("version");
-            this.rulesResponse.writeString(this.serverInterface.getServerVersion());
+            this.rulesResponse.writeString(queryResponse.getGameVersion());
             this.rulesResponse.writeString("plugins");
-            this.rulesResponse.writeString(this.serverInterface.getPluginNames());
+            java.lang.StringBuilder pluginsString = new java.lang.StringBuilder();
+            pluginsString.append(queryResponse.getServerVersion());
+            if (!queryResponse.getPlugins().isEmpty()) {
+                pluginsString.append(": ");
+                java.util.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().replace(";", ","));
+                    }
+                    if (iter.hasNext()) {
+                        pluginsString.append(';').append(' ');
+                    }
+                }
+            }
+            this.rulesResponse.writeString(pluginsString.toString());
             this.rulesResponse.writeString("map");
-            this.rulesResponse.writeString(this.worldName);
+            this.rulesResponse.writeString(queryResponse.getMap());
             this.rulesResponse.writeString("numplayers");
-            this.rulesResponse.writeString("" + this.serverInterface.getPlayerCount());
+            this.rulesResponse.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
             this.rulesResponse.writeString("maxplayers");
-            this.rulesResponse.writeString("" + this.maxPlayers);
+            this.rulesResponse.writeString(Integer.toString(queryResponse.getMaxPlayers()));
             this.rulesResponse.writeString("hostport");
-            this.rulesResponse.writeString("" + this.serverPort);
+            this.rulesResponse.writeString(Integer.toString(queryResponse.getPort()));
             this.rulesResponse.writeString("hostip");
-            this.rulesResponse.writeString(this.hostIp);
+            this.rulesResponse.writeString(queryResponse.getHostname());
             this.rulesResponse.write(0);
             this.rulesResponse.write(1);
             this.rulesResponse.writeString("player_");
             this.rulesResponse.write(0);
-            String[] strings = this.serverInterface.getPlayerNames();
+            String[] strings = queryResponse.getPlayers().toArray(String[]::new);
 
             for(String string : strings) {
                 this.rulesResponse.writeString(string);