From aca368e33230e25eb4a80a929d6f833bf1d9899f Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Mon, 19 Feb 2024 22:25:49 +0100 Subject: [PATCH] Implemented ViaProxy bootstrap (#4201) * Implemented ViaProxy bootstrap * Applied requested changes to code * Override indra settings to Java 17 * Removed explicit java source/target version * Added ViaProxy artifact to build.yml * Added ViaProxy artifact to pullrequest.yml * Updated ViaProxy API usage * Implemented floodgate support for ViaProxy * Depend on stable ViaProxy release * Initialize command manager and ping passthrough before Geyser#start * Revert "Initialize command manager and ping passthrough before Geyser#start" This reverts commit 39356071c4d59d82469477f160919365f88d39c7. * Some ping passthrough improvements * Merged code properly * Updated ViaProxy API usage * Implemented better command handling * Updated ViaProxy and Geyser API usage * Combine bootstrap and plugin into one class * Minor code improvements * Call Geyser shutdown on plugin disable * Only call disable if Geyser was enabled once * Don't send two shutdown done messages * Use setter for enabled boolean --- .github/workflows/build.yml | 7 + .github/workflows/pullrequest.yml | 7 + .../geyser/api/util/PlatformType.java | 1 + bootstrap/viaproxy/build.gradle.kts | 26 ++ .../viaproxy/GeyserViaProxyConfiguration.java | 53 +++++ .../viaproxy/GeyserViaProxyDumpInfo.java | 67 ++++++ .../viaproxy/GeyserViaProxyLogger.java | 88 +++++++ .../platform/viaproxy/GeyserViaProxyMain.java | 45 ++++ .../viaproxy/GeyserViaProxyPlugin.java | 224 ++++++++++++++++++ .../viaproxy/src/main/resources/viaproxy.yml | 5 + .../kotlin/geyser.base-conventions.gradle.kts | 6 +- build.gradle.kts | 3 +- .../java/org/geysermc/geyser/GeyserImpl.java | 39 +-- .../java/JavaLoginDisconnectTranslator.java | 2 +- gradle/libs.versions.toml | 2 + settings.gradle.kts | 4 +- 16 files changed, 559 insertions(+), 20 deletions(-) create mode 100644 bootstrap/viaproxy/build.gradle.kts create mode 100644 bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java create mode 100644 bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java create mode 100644 bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java create mode 100644 bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java create mode 100644 bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java create mode 100644 bootstrap/viaproxy/src/main/resources/viaproxy.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c5c15248..827136b4a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,6 +77,13 @@ jobs: name: Geyser Velocity path: bootstrap/velocity/build/libs/Geyser-Velocity.jar if-no-files-found: error + - name: Archive artifacts (Geyser ViaProxy) + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 + if: success() + with: + name: Geyser ViaProxy + path: bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar + if-no-files-found: error - name: Publish to Maven Repository if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 797d68767..f2c8f5d8d 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -87,3 +87,10 @@ jobs: name: Geyser Velocity path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar if-no-files-found: error + - name: Archive artifacts (Geyser ViaProxy) + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 + if: success() + with: + name: Geyser ViaProxy + path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar + if-no-files-found: error diff --git a/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java b/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java index 815381d6b..1abdc0230 100644 --- a/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java +++ b/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java @@ -40,4 +40,5 @@ public record PlatformType(String platformName) { public static final PlatformType SPONGE = new PlatformType("Sponge"); public static final PlatformType STANDALONE = new PlatformType("Standalone"); public static final PlatformType VELOCITY = new PlatformType("Velocity"); + public static final PlatformType VIAPROXY = new PlatformType("ViaProxy"); } diff --git a/bootstrap/viaproxy/build.gradle.kts b/bootstrap/viaproxy/build.gradle.kts new file mode 100644 index 000000000..4d5d4f949 --- /dev/null +++ b/bootstrap/viaproxy/build.gradle.kts @@ -0,0 +1,26 @@ +dependencies { + api(projects.core) +} + +platformRelocate("net.kyori") +platformRelocate("org.yaml") +platformRelocate("it.unimi.dsi.fastutil") +platformRelocate("org.cloudburstmc.netty") + +// These dependencies are already present on the platform +provided(libs.viaproxy) + +application { + mainClass.set("org.geysermc.geyser.platform.viaproxy.GeyserViaProxyMain") +} + +tasks.withType { + archiveBaseName.set("Geyser-ViaProxy") + + dependencies { + exclude(dependency("com.google.*:.*")) + exclude(dependency("io.netty:.*")) + exclude(dependency("org.slf4j:.*")) + exclude(dependency("org.ow2.asm:.*")) + } +} diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java new file mode 100644 index 000000000..ad249eb3b --- /dev/null +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ +package org.geysermc.geyser.platform.viaproxy; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import net.raphimc.vialegacy.api.LegacyProtocolVersion; +import net.raphimc.viaproxy.cli.options.Options; +import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; + +import java.io.File; +import java.nio.file.Path; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration { + + @Override + public Path getFloodgateKeyPath() { + return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath(); + } + + @Override + public int getPingPassthroughInterval() { + int interval = super.getPingPassthroughInterval(); + if (interval < 15 && Options.PROTOCOL_VERSION != null && Options.PROTOCOL_VERSION.olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) { + // <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made + interval = 15; + } + return interval; + } + +} diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java new file mode 100644 index 000000000..08f3d5371 --- /dev/null +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ +package org.geysermc.geyser.platform.viaproxy; + +import lombok.Getter; +import net.raphimc.viaproxy.ViaProxy; +import net.raphimc.viaproxy.cli.options.Options; +import net.raphimc.viaproxy.plugins.ViaProxyPlugin; +import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.text.AsteriskSerializer; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Getter +public class GeyserViaProxyDumpInfo extends BootstrapDumpInfo { + + private final String platformVersion; + private final boolean onlineMode; + + @AsteriskSerializer.Asterisk(isIp = true) + private final String serverIP; + private final int serverPort; + private final List plugins; + + public GeyserViaProxyDumpInfo() { + this.platformVersion = ViaProxy.VERSION; + this.onlineMode = Options.ONLINE_MODE; + if (Options.BIND_ADDRESS instanceof InetSocketAddress inetSocketAddress) { + this.serverIP = inetSocketAddress.getHostString(); + this.serverPort = inetSocketAddress.getPort(); + } else { + this.serverIP = "unsupported"; + this.serverPort = 0; + } + this.plugins = new ArrayList<>(); + + for (ViaProxyPlugin plugin : ViaProxy.getPluginManager().getPlugins()) { + this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion(), "unknown", Collections.singletonList(plugin.getAuthor()))); + } + } + +} diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java new file mode 100644 index 000000000..10f414b51 --- /dev/null +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ +package org.geysermc.geyser.platform.viaproxy; + +import net.raphimc.viaproxy.cli.ConsoleFormatter; +import org.apache.logging.log4j.Logger; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.command.GeyserCommandSource; + +public class GeyserViaProxyLogger implements GeyserLogger, GeyserCommandSource { + + private final Logger logger; + private boolean debug; + + public GeyserViaProxyLogger(Logger logger) { + this.logger = logger; + } + + @Override + public void severe(String message) { + this.logger.fatal(ConsoleFormatter.convert(message)); + } + + @Override + public void severe(String message, Throwable error) { + this.logger.fatal(ConsoleFormatter.convert(message), error); + } + + @Override + public void error(String message) { + this.logger.error(ConsoleFormatter.convert(message)); + } + + @Override + public void error(String message, Throwable error) { + this.logger.error(ConsoleFormatter.convert(message), error); + } + + @Override + public void warning(String message) { + this.logger.warn(ConsoleFormatter.convert(message)); + } + + @Override + public void info(String message) { + this.logger.info(ConsoleFormatter.convert(message)); + } + + @Override + public void debug(String message) { + if (this.debug) { + this.logger.debug(ConsoleFormatter.convert(message)); + } + } + + @Override + public void setDebug(boolean debug) { + this.debug = debug; + } + + @Override + public boolean isDebug() { + return this.debug; + } + +} diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java new file mode 100644 index 000000000..675c92534 --- /dev/null +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.viaproxy; + +import net.raphimc.viaproxy.plugins.PluginManager; +import org.geysermc.geyser.GeyserMain; + +public class GeyserViaProxyMain extends GeyserMain { + + public static void main(String[] args) { + new GeyserViaProxyMain().displayMessage(); + } + + public String getPluginType() { + return "ViaProxy"; + } + + public String getPluginFolder() { + return PluginManager.PLUGINS_DIR.getName(); + } + +} diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java new file mode 100644 index 000000000..47745df7d --- /dev/null +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ +package org.geysermc.geyser.platform.viaproxy; + +import net.lenni0451.lambdaevents.EventHandler; +import net.raphimc.vialegacy.api.LegacyProtocolVersion; +import net.raphimc.viaproxy.ViaProxy; +import net.raphimc.viaproxy.cli.options.Options; +import net.raphimc.viaproxy.plugins.PluginManager; +import net.raphimc.viaproxy.plugins.ViaProxyPlugin; +import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent; +import net.raphimc.viaproxy.plugins.events.ProxyStartEvent; +import net.raphimc.viaproxy.plugins.events.ProxyStopEvent; +import net.raphimc.viaproxy.plugins.events.ShouldVerifyOnlineModeEvent; +import org.apache.logging.log4j.LogManager; +import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.api.network.AuthType; +import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; +import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.session.GeyserSession; +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; +import java.net.InetSocketAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; + +public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap { + + public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser"); + + private final GeyserViaProxyLogger logger = new GeyserViaProxyLogger(LogManager.getLogger("Geyser")); + private GeyserViaProxyConfiguration config; + private GeyserImpl geyser; + private GeyserCommandManager commandManager; + private IGeyserPingPassthrough pingPassthrough; + + @Override + public void onEnable() { + ROOT_FOLDER.mkdirs(); + + GeyserLocale.init(this); + this.onGeyserInitialize(); + + ViaProxy.EVENT_MANAGER.register(this); + } + + @Override + public void onDisable() { + this.onGeyserShutdown(); + } + + @EventHandler + private void onConsoleCommand(final ConsoleCommandEvent event) { + final String command = event.getCommand().startsWith("/") ? event.getCommand().substring(1) : event.getCommand(); + if (this.getGeyserCommandManager().runCommand(this.getGeyserLogger(), command + " " + String.join(" ", event.getArgs()))) { + event.setCancelled(true); + } + } + + @EventHandler + private void onShouldVerifyOnlineModeEvent(final ShouldVerifyOnlineModeEvent event) { + final UUID uuid = event.getProxyConnection().getGameProfile().getId(); + if (uuid == null) return; + + final GeyserSession connection = GeyserImpl.getInstance().onlineConnections().stream().filter(s -> s.javaUuid().equals(uuid)).findAny().orElse(null); + if (connection == null) return; + + if (connection.javaUsername().equals(event.getProxyConnection().getGameProfile().getName())) { + event.setCancelled(true); + } + } + + @EventHandler + private void onProxyStart(final ProxyStartEvent event) { + this.onGeyserEnable(); + } + + @EventHandler + private void onProxyStop(final ProxyStopEvent event) { + this.onGeyserDisable(); + } + + @Override + public void onGeyserInitialize() { + if (!this.loadConfig()) { + return; + } + + this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this); + LoopbackUtil.checkAndApplyLoopback(this.logger); + } + + @Override + public void onGeyserEnable() { + if (GeyserImpl.getInstance().isReloading()) { + if (!this.loadConfig()) { + return; + } + } + + this.commandManager = new GeyserCommandManager(this.geyser); + this.commandManager.init(); + + GeyserImpl.start(); + + if (Options.PROTOCOL_VERSION != null && Options.PROTOCOL_VERSION.newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) { + // Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added + this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser); + } + } + + @Override + public void onGeyserDisable() { + this.geyser.disable(); + } + + @Override + public void onGeyserShutdown() { + this.geyser.shutdown(); + } + + @Override + public GeyserConfiguration getGeyserConfig() { + return this.config; + } + + @Override + public GeyserLogger getGeyserLogger() { + return this.logger; + } + + @Override + public GeyserCommandManager getGeyserCommandManager() { + return this.commandManager; + } + + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return this.pingPassthrough; + } + + @Override + public Path getConfigFolder() { + return ROOT_FOLDER.toPath(); + } + + @Override + public BootstrapDumpInfo getDumpInfo() { + return new GeyserViaProxyDumpInfo(); + } + + @NotNull + @Override + public String getServerBindAddress() { + if (Options.BIND_ADDRESS instanceof InetSocketAddress socketAddress) { + return socketAddress.getHostString(); + } else { + throw new IllegalStateException("Unsupported bind address type: " + Options.BIND_ADDRESS.getClass().getName()); + } + } + + @Override + public int getServerPort() { + if (Options.BIND_ADDRESS instanceof InetSocketAddress socketAddress) { + return socketAddress.getPort(); + } else { + throw new IllegalStateException("Unsupported bind address type: " + Options.BIND_ADDRESS.getClass().getName()); + } + } + + @Override + public boolean testFloodgatePluginPresent() { + return false; + } + + private boolean loadConfig() { + try { + final File configFile = FileUtils.fileOrCopiedFromResource(new File(ROOT_FOLDER, "config.yml"), "config.yml", s -> s.replaceAll("generateduuid", UUID.randomUUID().toString()), this); + this.config = FileUtils.loadConfig(configFile, GeyserViaProxyConfiguration.class); + } catch (IOException e) { + this.logger.severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), e); + return false; + } + this.config.getRemote().setAuthType(Files.isRegularFile(this.config.getFloodgateKeyPath()) ? AuthType.FLOODGATE : AuthType.OFFLINE); + this.logger.setDebug(this.config.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(this.config, this.logger); + return true; + } + +} diff --git a/bootstrap/viaproxy/src/main/resources/viaproxy.yml b/bootstrap/viaproxy/src/main/resources/viaproxy.yml new file mode 100644 index 000000000..f42cda77b --- /dev/null +++ b/bootstrap/viaproxy/src/main/resources/viaproxy.yml @@ -0,0 +1,5 @@ +name: "${name}-ViaProxy" +version: "${version}" +author: "${author}" +main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin" +min-version: "3.2.0" diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 01c769733..c9f984596 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -22,8 +22,8 @@ indra { tasks { processResources { - // Spigot, BungeeCord, Velocity, Fabric - filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) { + // Spigot, BungeeCord, Velocity, Fabric, ViaProxy + filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml")) { expand( "id" to "geyser", "name" to "Geyser", @@ -34,4 +34,4 @@ tasks { ) } } -} \ No newline at end of file +} diff --git a/build.gradle.kts b/build.gradle.kts index a72b8a484..1d434e599 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,7 +23,8 @@ val platforms = setOf( projects.bungeecord, projects.spigot, projects.standalone, - projects.velocity + projects.velocity, + projects.viaproxy ).map { it.dependencyProject } subprojects { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 5ed0c3947..6a8efaba1 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -44,9 +44,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.geysermc.api.Geyser; -import org.geysermc.geyser.api.command.CommandSource; -import org.geysermc.geyser.api.util.MinecraftVersion; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.erosion.packet.Packets; @@ -56,12 +53,15 @@ import org.geysermc.floodgate.crypto.Base64Topping; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.news.NewsItemAction; import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.lifecycle.*; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; +import org.geysermc.geyser.api.util.MinecraftVersion; +import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; @@ -169,6 +169,12 @@ public class GeyserImpl implements GeyserApi { */ private volatile boolean isReloading; + /** + * Determines if Geyser is currently enabled. This is used to determine if {@link #disable()} should be called during {@link #shutdown()}. + */ + @Setter + private boolean isEnabled; + private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap) { instance = this; @@ -344,15 +350,17 @@ public class GeyserImpl implements GeyserApi { logger.info("Broadcast port set from system property: " + parsedPort); } - boolean floodgatePresent = bootstrap.testFloodgatePluginPresent(); - if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " - + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (config.isAutoconfiguredRemote() && floodgatePresent) { - // Floodgate installed means that the user wants Floodgate authentication - logger.debug("Auto-setting to Floodgate authentication."); - config.getRemote().setAuthType(AuthType.FLOODGATE); + if (platformType != PlatformType.VIAPROXY) { + boolean floodgatePresent = bootstrap.testFloodgatePluginPresent(); + if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { + logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); + return; + } else if (config.isAutoconfiguredRemote() && floodgatePresent) { + // Floodgate installed means that the user wants Floodgate authentication + logger.debug("Auto-setting to Floodgate authentication."); + config.getRemote().setAuthType(AuthType.FLOODGATE); + } } } @@ -639,12 +647,14 @@ public class GeyserImpl implements GeyserApi { Registries.RESOURCE_PACKS.get().clear(); - bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); + this.setEnabled(false); } public void shutdown() { shuttingDown = true; - this.disable(); + if (isEnabled) { + this.disable(); + } this.commandManager().getCommands().clear(); // Disable extensions, fire the shutdown event @@ -777,6 +787,7 @@ public class GeyserImpl implements GeyserApi { } else { instance.initialize(); } + instance.setEnabled(true); } public GeyserLogger getLogger() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java index daf42a68e..c0be2c624 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java @@ -51,7 +51,7 @@ public class JavaLoginDisconnectTranslator extends PacketTranslator