Paper/Spigot-API-Patches/0174-Add-GS4-Query-event.patch
Aikar 36f34f01c0
Updated Upstream (Bukkit/CraftBukkit)
Upstream has released updates that appears to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
da9ef3c5 #496: Add methods to get/set ItemStacks in EquipmentSlots
3abebc9f #492: Let Tameable extend Animals rather than Entity
941111a0 #495: Expose ItemStack and hand used in PlayerShearEntityEvent
4fe19cae #494: InventoryView - Add missing Brewing FUEL_TIME

CraftBukkit Changes:
933e9094 #664: Add methods to get/set ItemStacks in EquipmentSlots
18722312 #662: Expose ItemStack and hand used in PlayerShearEntityEvent
2020-05-06 06:05:22 -04:00

425 lines
13 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
Date: Sun, 17 Mar 2019 21:46:27 +0200
Subject: [PATCH] Add GS4 Query event
diff --git a/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..77a19995f6792a182c5a43d6714e7bda0f42df5b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java
@@ -0,0 +1,412 @@
+package com.destroystokyo.paper.event.server;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * This event is fired if server is getting queried over GS4 Query protocol
+ *
+ * Adapted from Velocity's ProxyQueryEvent
+ *
+ * @author Mark Vainomaa
+ */
+public final class GS4QueryEvent extends Event {
+ private static final HandlerList handlers = new HandlerList();
+
+ private final QueryType queryType;
+ private final InetAddress querierAddress;
+ private QueryResponse response;
+
+ public GS4QueryEvent(@NotNull QueryType queryType, @NotNull InetAddress querierAddress, @NotNull QueryResponse response) {
+ super(true); // should always be called async
+ this.queryType = Preconditions.checkNotNull(queryType, "queryType");
+ this.querierAddress = Preconditions.checkNotNull(querierAddress, "querierAddress");
+ this.response = Preconditions.checkNotNull(response, "response");
+ }
+
+ /**
+ * Get query type
+ * @return query type
+ */
+ @NotNull
+ public QueryType getQueryType() {
+ return queryType;
+ }
+
+ /**
+ * Get querier address
+ * @return querier address
+ */
+ @NotNull
+ public InetAddress getQuerierAddress() {
+ return querierAddress;
+ }
+
+ /**
+ * Get query response
+ * @return query response
+ */
+ @NotNull
+ public QueryResponse getResponse() {
+ return response;
+ }
+
+ /**
+ * Set query response
+ * @param response query response
+ */
+ public void setResponse(@NotNull QueryResponse response) {
+ this.response = Preconditions.checkNotNull(response, "response");
+ }
+
+ @Override
+ public String toString() {
+ return "GS4QueryEvent{" +
+ "queryType=" + queryType +
+ ", querierAddress=" + querierAddress +
+ ", response=" + response +
+ '}';
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+ /**
+ * The type of query
+ */
+ public enum QueryType {
+ /**
+ * Basic query asks only a subset of information, such as motd, game type (hardcoded to <pre>MINECRAFT</pre>), map,
+ * current players, max players, server port and server motd
+ */
+ BASIC,
+
+ /**
+ * Full query asks pretty much everything present on this event (only hardcoded values cannot be modified here).
+ */
+ FULL
+ ;
+ }
+
+ public final static class QueryResponse {
+ private final String motd;
+ private final String gameVersion;
+ private final String map;
+ private final int currentPlayers;
+ private final int maxPlayers;
+ private final String hostname;
+ private final int port;
+ private final Collection<String> players;
+ private final String serverVersion;
+ private final Collection<PluginInformation> plugins;
+
+ private QueryResponse(String motd, String gameVersion, String map, int currentPlayers, int maxPlayers, String hostname, int port, Collection<String> players, String serverVersion, Collection<PluginInformation> plugins) {
+ this.motd = motd;
+ this.gameVersion = gameVersion;
+ this.map = map;
+ this.currentPlayers = currentPlayers;
+ this.maxPlayers = maxPlayers;
+ this.hostname = hostname;
+ this.port = port;
+ this.players = players;
+ this.serverVersion = serverVersion;
+ this.plugins = plugins;
+ }
+
+ /**
+ * Get motd which will be used to reply to the query. By default it is {@link org.bukkit.Server#getMotd()}.
+ * @return motd
+ */
+ @NotNull
+ public String getMotd() {
+ return motd;
+ }
+
+ /**
+ * Get game version which will be used to reply to the query. By default supported Minecraft versions range is sent.
+ * @return game version
+ */
+ @NotNull
+ public String getGameVersion() {
+ return gameVersion;
+ }
+
+ /**
+ * Get map name which will be used to reply to the query. By default {@code world} is sent.
+ * @return map name
+ */
+ @NotNull
+ public String getMap() {
+ return map;
+ }
+
+ /**
+ * Get current online player count which will be used to reply to the query.
+ * @return online player count
+ */
+ public int getCurrentPlayers() {
+ return currentPlayers;
+ }
+
+ /**
+ * Get max player count which will be used to reply to the query.
+ * @return max player count
+ */
+ public int getMaxPlayers() {
+ return maxPlayers;
+ }
+
+ /**
+ * Get server (public facing) hostname
+ * @return server hostname
+ */
+ @NotNull
+ public String getHostname() {
+ return hostname;
+ }
+
+ /**
+ * Get server (public facing) port
+ * @return server port
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Get collection of players which will be used to reply to the query.
+ * @return collection of players
+ */
+ @NotNull
+ public Collection<String> getPlayers() {
+ return players;
+ }
+
+ /**
+ * Get server software (name and version) which will be used to reply to the query.
+ * @return server software
+ */
+ @NotNull
+ public String getServerVersion() {
+ return serverVersion;
+ }
+
+ /**
+ * Get list of plugins which will be used to reply to the query.
+ * @return collection of plugins
+ */
+ @NotNull
+ public Collection<PluginInformation> getPlugins() {
+ return plugins;
+ }
+
+
+ /**
+ * Creates a new {@link Builder} instance from data represented by this response
+ * @return {@link QueryResponse} builder
+ */
+ @NotNull
+ public Builder toBuilder() {
+ return QueryResponse.builder()
+ .motd(getMotd())
+ .gameVersion(getGameVersion())
+ .map(getMap())
+ .currentPlayers(getCurrentPlayers())
+ .maxPlayers(getMaxPlayers())
+ .hostname(getHostname())
+ .port(getPort())
+ .players(getPlayers())
+ .serverVersion(getServerVersion())
+ .plugins(getPlugins());
+ }
+
+ /**
+ * Creates a new {@link Builder} instance
+ * @return {@link QueryResponse} builder
+ */
+ @NotNull
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * A builder for {@link QueryResponse} objects.
+ */
+ public static final class Builder {
+ private String motd;
+ private String gameVersion;
+ private String map;
+ private String hostname;
+ private String serverVersion;
+
+ private int currentPlayers;
+ private int maxPlayers;
+ private int port;
+
+ private List<String> players = new ArrayList<>();
+ private List<PluginInformation> plugins = new ArrayList<>();
+
+ private Builder() {}
+
+ @NotNull
+ public Builder motd(@NotNull String motd) {
+ this.motd = Preconditions.checkNotNull(motd, "motd");
+ return this;
+ }
+
+ @NotNull
+ public Builder gameVersion(@NotNull String gameVersion) {
+ this.gameVersion = Preconditions.checkNotNull(gameVersion, "gameVersion");
+ return this;
+ }
+
+ @NotNull
+ public Builder map(@NotNull String map) {
+ this.map = Preconditions.checkNotNull(map, "map");
+ return this;
+ }
+
+ @NotNull
+ public Builder currentPlayers(int currentPlayers) {
+ Preconditions.checkArgument(currentPlayers >= 0, "currentPlayers cannot be negative");
+ this.currentPlayers = currentPlayers;
+ return this;
+ }
+
+ @NotNull
+ public Builder maxPlayers(int maxPlayers) {
+ Preconditions.checkArgument(maxPlayers >= 0, "maxPlayers cannot be negative");
+ this.maxPlayers = maxPlayers;
+ return this;
+ }
+
+ @NotNull
+ public Builder hostname(@NotNull String hostname) {
+ this.hostname = Preconditions.checkNotNull(hostname, "hostname");
+ return this;
+ }
+
+ @NotNull
+ public Builder port(int port) {
+ Preconditions.checkArgument(port >= 1 && port <= 65535, "port must be between 1-65535");
+ this.port = port;
+ return this;
+ }
+
+ @NotNull
+ public Builder players(@NotNull Collection<String> players) {
+ this.players.addAll(Preconditions.checkNotNull(players, "players"));
+ return this;
+ }
+
+ @NotNull
+ public Builder players(@NotNull String... players) {
+ this.players.addAll(Arrays.asList(Preconditions.checkNotNull(players, "players")));
+ return this;
+ }
+
+ @NotNull
+ public Builder clearPlayers() {
+ this.players.clear();
+ return this;
+ }
+
+ @NotNull
+ public Builder serverVersion(@NotNull String serverVersion) {
+ this.serverVersion = Preconditions.checkNotNull(serverVersion, "serverVersion");
+ return this;
+ }
+
+ @NotNull
+ public Builder plugins(@NotNull Collection<PluginInformation> plugins) {
+ this.plugins.addAll(Preconditions.checkNotNull(plugins, "plugins"));
+ return this;
+ }
+
+ @NotNull
+ public Builder plugins(@NotNull PluginInformation... plugins) {
+ this.plugins.addAll(Arrays.asList(Preconditions.checkNotNull(plugins, "plugins")));
+ return this;
+ }
+
+ @NotNull
+ public Builder clearPlugins() {
+ this.plugins.clear();
+ return this;
+ }
+
+ /**
+ * Builds new {@link QueryResponse} with supplied data
+ * @return response
+ */
+ @NotNull
+ public QueryResponse build() {
+ return new QueryResponse(
+ Preconditions.checkNotNull(motd, "motd"),
+ Preconditions.checkNotNull(gameVersion, "gameVersion"),
+ Preconditions.checkNotNull(map, "map"),
+ currentPlayers,
+ maxPlayers,
+ Preconditions.checkNotNull(hostname, "hostname"),
+ port,
+ ImmutableList.copyOf(players),
+ Preconditions.checkNotNull(serverVersion, "serverVersion"),
+ ImmutableList.copyOf(plugins)
+ );
+ }
+ }
+
+ /**
+ * Plugin information
+ */
+ public static class PluginInformation {
+ private String name;
+ private String version;
+
+ public PluginInformation(@NotNull String name, @NotNull String version) {
+ this.name = Preconditions.checkNotNull(name, "name");
+ this.version = Preconditions.checkNotNull(version, "version");
+ }
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ public void setName(@NotNull String name) {
+ this.name = name;
+ }
+
+ public void setVersion(@NotNull String version) {
+ this.version = version;
+ }
+
+ @NotNull
+ public String getVersion() {
+ return version;
+ }
+
+ @NotNull
+ public static PluginInformation of(@NotNull String name, @NotNull String version) {
+ return new PluginInformation(name, version);
+ }
+ }
+ }
+}