From f39e689b83c1be89ec4f51ab9fc60b9c419b7b99 Mon Sep 17 00:00:00 2001 From: Julian Vennen <julian@aternos.org> Date: Sun, 23 Apr 2023 03:33:23 +0200 Subject: [PATCH] Implement System properties to set the udp port and address #3597 (#3689) * System property stuff * Add geyserUdpPort/Address system properties as overrides for pluginUdpPort/Address * Fix formatting for if-else statements --------- Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../bungeecord/GeyserBungeePlugin.java | 40 +++++------ .../platform/fabric/GeyserFabricMod.java | 26 ++++--- .../platform/spigot/GeyserSpigotPlugin.java | 60 ++++------------ .../platform/sponge/GeyserSpongePlugin.java | 30 ++++---- .../standalone/GeyserStandaloneBootstrap.java | 12 ++++ .../velocity/GeyserVelocityPlugin.java | 29 ++++---- .../org/geysermc/geyser/GeyserBootstrap.java | 11 +++ .../java/org/geysermc/geyser/GeyserImpl.java | 70 ++++++++++++++++--- .../configuration/GeyserConfiguration.java | 7 ++ .../GeyserJacksonConfiguration.java | 4 +- 10 files changed, 160 insertions(+), 129 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index dc7602163..518e461cb 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -45,6 +45,7 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; @@ -55,6 +56,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -116,26 +118,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { return; } - if (getProxy().getConfig().getListeners().size() == 1) { - ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0]; - - InetSocketAddress javaAddr = listener.getHost(); - - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { - this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); - } - this.geyserConfig.getRemote().setPort(javaAddr.getPort()); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(javaAddr.getPort()); - } - } - // Force-disable query if enabled, or else Geyser won't enable for (ListenerInfo info : getProxy().getConfig().getListeners()) { if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) { @@ -274,4 +256,22 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public SocketAddress getSocketAddress() { return this.geyserInjector.getServerSocketAddress(); } + + @NotNull + @Override + public String getServerBindAddress() { + return findCompatibleListener().map(InetSocketAddress::getHostString).orElse(""); + } + + @Override + public int getServerPort() { + return findCompatibleListener().stream().mapToInt(InetSocketAddress::getPort).findFirst().orElse(-1); + } + + private Optional<InetSocketAddress> findCompatibleListener() { + return getProxy().getConfig().getListeners().stream() + .filter(info -> info.getSocketAddress() instanceof InetSocketAddress) + .map(info -> (InetSocketAddress) info.getSocketAddress()) + .findFirst(); + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index e5ff4b577..355777da1 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -53,6 +53,7 @@ import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -138,20 +139,6 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { public void startGeyser(MinecraftServer server) { this.server = server; - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - String ip = server.getLocalIp(); - int port = ((GeyserServerPortGetter) server).geyser$getServerPort(); - if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { - this.geyserConfig.getRemote().setAddress(ip); - } - this.geyserConfig.getRemote().setPort(port); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port()); - } - Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate"); boolean floodgatePresent = floodgate.isPresent(); if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { @@ -242,6 +229,17 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return this.server.getServerVersion(); } + @NotNull + @Override + public String getServerBindAddress() { + return this.server.getLocalIp(); + } + + @Override + public int getServerPort() { + return ((GeyserServerPortGetter) server).geyser$getServerPort(); + } + @Nullable @Override public InputStream getResourceOrNull(String resource) { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 1be2eb32a..88b006851 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -65,6 +65,7 @@ import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; import org.geysermc.geyser.platform.spigot.world.manager.*; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; @@ -170,20 +171,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return; } - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { - geyserConfig.getRemote().setAddress(Bukkit.getIp()); - } - geyserConfig.getRemote().setPort(Bukkit.getPort()); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(Bukkit.getPort()); - } - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); this.getPluginLoader().disablePlugin(this); @@ -431,40 +418,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return this.geyserInjector.getServerSocketAddress(); } - public boolean isCompatible(String version, String whichVersion) { - int[] currentVersion = parseVersion(version); - int[] otherVersion = parseVersion(whichVersion); - int length = Math.max(currentVersion.length, otherVersion.length); - for (int index = 0; index < length; index = index + 1) { - int self = (index < currentVersion.length) ? currentVersion[index] : 0; - int other = (index < otherVersion.length) ? otherVersion[index] : 0; - - if (self != other) { - return (self - other) > 0; - } - } - return true; - } - - private int[] parseVersion(String versionParam) { - versionParam = (versionParam == null) ? "" : versionParam; - if (versionParam.contains("(MC: ")) { - versionParam = versionParam.split("\\(MC: ")[1]; - versionParam = versionParam.split("\\)")[0]; - } - String[] stringArray = versionParam.split("[_.-]"); - int[] temp = new int[stringArray.length]; - for (int index = 0; index <= (stringArray.length - 1); index = index + 1) { - String t = stringArray[index].replaceAll("\\D", ""); - try { - temp[index] = Integer.parseInt(t); - } catch (NumberFormatException ex) { - temp[index] = 0; - } - } - return temp; - } - /** * @return the server version before ViaVersion finishes initializing */ @@ -494,4 +447,15 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { // All mapping data is null, which means client and server block states are the same return false; } + + @NotNull + @Override + public String getServerBindAddress() { + return Bukkit.getIp(); + } + + @Override + public int getServerPort() { + return Bukkit.getPort(); + } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index 1f9541631..a87b51820 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -41,6 +41,7 @@ import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor; +import org.jetbrains.annotations.NotNull; import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; import org.spongepowered.api.config.ConfigDir; @@ -179,24 +180,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap { return; } - if (Sponge.server().boundAddress().isPresent()) { - InetSocketAddress javaAddr = Sponge.server().boundAddress().get(); - - // By default this should be 127.0.0.1 but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - // Don't change the ip if its listening on all interfaces - if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { - this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); - } - geyserConfig.getRemote().setPort(javaAddr.getPort()); - } - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port()); - } - GeyserImpl.start(); if (geyserConfig.isLegacyPingPassthrough()) { @@ -245,4 +228,15 @@ public class GeyserSpongePlugin implements GeyserBootstrap { public String getMinecraftServerVersion() { return Sponge.platform().minecraftVersion().name(); } + + @NotNull + @Override + public String getServerBindAddress() { + return Sponge.server().boundAddress().map(InetSocketAddress::getHostString).orElse(""); + } + + @Override + public int getServerPort() { + return Sponge.server().boundAddress().stream().mapToInt(InetSocketAddress::getPort).findFirst().orElse(-1); + } } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 5cbbab9d4..e99ba98bc 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -51,6 +51,7 @@ import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.LoopbackUtil; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; @@ -291,6 +292,17 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { return new GeyserStandaloneDumpInfo(this); } + @NotNull + @Override + public String getServerBindAddress() { + throw new IllegalStateException(); + } + + @Override + public int getServerPort() { + throw new IllegalStateException(); + } + /** * Get the {@link BeanPropertyDefinition}s for the given class * diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 5ac09416c..41e797d48 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -50,12 +50,12 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import java.io.File; import java.io.IOException; -import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; @@ -111,22 +111,6 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { return; } - InetSocketAddress javaAddr = proxyServer.getBoundAddress(); - - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { - this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); - } - geyserConfig.getRemote().setPort(javaAddr.getPort()); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(javaAddr.getPort()); - } - this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); @@ -247,4 +231,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { public SocketAddress getSocketAddress() { return this.geyserInjector.getServerSocketAddress(); } + + @NotNull + @Override + public String getServerBindAddress() { + return proxyServer.getBoundAddress().getHostString(); + } + + @Override + public int getServerPort() { + return proxyServer.getBoundAddress().getPort(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java index 261c7416b..46abf4f1e 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java @@ -158,4 +158,15 @@ public interface GeyserBootstrap { } return stream; } + + /** + * @return the bind address being used by the Java server. + */ + @Nonnull + String getServerBindAddress(); + + /** + * @return the listening port being used by the Java server. -1 if can't be found + */ + int getServerPort(); } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 78d538422..4d7958e16 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -261,16 +261,68 @@ public class GeyserImpl implements GeyserApi { ResourcePack.loadPacks(); - if (platformType != PlatformType.STANDALONE && config.getRemote().address().equals("auto")) { - // Set the remote address to localhost since that is where we are always connecting - try { - config.getRemote().setAddress(InetAddress.getLocalHost().getHostAddress()); - } catch (UnknownHostException ex) { - logger.debug("Unknown host when trying to find localhost."); - if (config.isDebugMode()) { - ex.printStackTrace(); + String geyserUdpPort = System.getProperty("geyserUdpPort", ""); + String pluginUdpPort = geyserUdpPort.isEmpty() ? System.getProperty("pluginUdpPort", "") : geyserUdpPort; + if ("-1".equals(pluginUdpPort)) { + throw new UnsupportedOperationException("This hosting/service provider does not support applications running on the UDP port"); + } + boolean portPropertyApplied = false; + String pluginUdpAddress = System.getProperty("geyserUdpAddress", System.getProperty("pluginUdpAddress", "")); + + if (platformType != PlatformType.STANDALONE) { + int javaPort = bootstrap.getServerPort(); + if (config.getRemote().address().equals("auto")) { + config.setAutoconfiguredRemote(true); + String serverAddress = bootstrap.getServerBindAddress(); + if (!serverAddress.isEmpty() && !"0.0.0.0".equals(serverAddress)) { + config.getRemote().setAddress(serverAddress); + } else { + // Set the remote address to localhost since that is where we are always connecting + try { + config.getRemote().setAddress(InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException ex) { + logger.debug("Unknown host when trying to find localhost."); + if (config.isDebugMode()) { + ex.printStackTrace(); + } + config.getRemote().setAddress(InetAddress.getLoopbackAddress().getHostAddress()); + } + } + if (javaPort != -1) { + config.getRemote().setPort(javaPort); + } + } + + boolean forceMatchServerPort = "server".equals(pluginUdpPort); + if ((config.getBedrock().isCloneRemotePort() || forceMatchServerPort) && javaPort != -1) { + config.getBedrock().setPort(javaPort); + if (forceMatchServerPort) { + if (geyserUdpPort.isEmpty()) { + logger.info("Port set from system generic property to match Java server."); + } else { + logger.info("Port set from system property to match Java server."); + } + portPropertyApplied = true; + } + } + + if ("server".equals(pluginUdpAddress)) { + String address = bootstrap.getServerBindAddress(); + if (!address.isEmpty()) { + config.getBedrock().setAddress(address); + } + } else if (!pluginUdpAddress.isEmpty()) { + config.getBedrock().setAddress(pluginUdpAddress); + } + + if (!portPropertyApplied && !pluginUdpPort.isEmpty()) { + int port = Integer.parseInt(pluginUdpPort); + config.getBedrock().setPort(port); + if (geyserUdpPort.isEmpty()) { + logger.info("Port set from generic system property: " + port); + } else { + logger.info("Port set from system property: " + port); } - config.getRemote().setAddress(InetAddress.getLoopbackAddress().getHostAddress()); } } String remoteAddress = config.getRemote().address(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index ea4c31876..2b0f193a7 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -38,6 +38,10 @@ import java.util.List; import java.util.Map; public interface GeyserConfiguration { + /** + * If the config was originally 'auto' before the values changed + */ + void setAutoconfiguredRemote(boolean autoconfiguredRemote); // Modify this when you introduce breaking changes into the config int CURRENT_CONFIG_VERSION = 4; @@ -116,6 +120,9 @@ public interface GeyserConfiguration { int getPendingAuthenticationTimeout(); interface IBedrockConfiguration extends BedrockListener { + void setAddress(String address); + + void setPort(int port); boolean isCloneRemotePort(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index bbfa37ec2..e096d58fa 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -53,9 +53,6 @@ import java.util.stream.Collectors; @SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final public abstract class GeyserJacksonConfiguration implements GeyserConfiguration { - /** - * If the config was originally 'auto' before the values changed - */ @Setter private boolean autoconfiguredRemote = false; @@ -163,6 +160,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration public static class BedrockConfiguration implements IBedrockConfiguration { @AsteriskSerializer.Asterisk(isIp = true) @JsonProperty("address") + @Setter private String address = "0.0.0.0"; @Override