From 00eaec89037216a6be13ec3735086602b83eef84 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 27 Jan 2022 11:34:59 +0100 Subject: [PATCH 001/113] Updated Cumulus to 1.1 --- .../geysermc/floodgate/api/FloodgateApi.java | 4 ++-- .../floodgate/api/player/FloodgatePlayer.java | 4 ++-- build-logic/src/main/kotlin/Versions.kt | 22 +++++++++---------- .../floodgate/api/SimpleFloodgateApi.java | 4 ++-- .../pluginmessage/channel/FormChannel.java | 21 ++++++++++++++---- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java index 45171ab6..38f368d8 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java +++ b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java @@ -28,7 +28,7 @@ import java.util.Collection; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.geysermc.cumulus.Form; +import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.util.FormBuilder; import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -94,7 +94,7 @@ static FloodgateApi getInstance() { boolean sendForm(UUID uuid, Form form); - boolean sendForm(UUID uuid, FormBuilder formBuilder); + boolean sendForm(UUID uuid, FormBuilder formBuilder); boolean transferPlayer(UUID uuid, String address, int port); diff --git a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java index 8ade2d12..584e2943 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java +++ b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java @@ -26,7 +26,7 @@ package org.geysermc.floodgate.api.player; import java.util.UUID; -import org.geysermc.cumulus.Form; +import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.util.FormBuilder; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.util.DeviceOs; @@ -115,7 +115,7 @@ default boolean sendForm(Form form) { return FloodgateApi.getInstance().sendForm(getCorrectUniqueId(), form); } - default boolean sendForm(FormBuilder formBuilder) { + default boolean sendForm(FormBuilder formBuilder) { return sendForm(formBuilder.build()); } diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 4ce4c6f4..74b115c6 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,17 +24,17 @@ */ object Versions { - const val geyserVersion= "2.0.0-SNAPSHOT" - const val cumulusVersion= "1.0-SNAPSHOT" - const val spigotVersion= "1.13-R0.1-SNAPSHOT" - const val fastutilVersion= "8.5.3" - const val lombokVersion= "1.18.20" - const val guiceVersion= "5.0.1" - const val nettyVersion= "4.1.49.Final" - const val snakeyamlVersion= "1.28" - const val cloudVersion= "1.5.0" - const val adventureApiVersion= "4.9.1" - const val adventurePlatformVersion= "4.0.0" + const val geyserVersion = "2.0.1-cumulus-SNAPSHOT" + const val cumulusVersion = "1.1-SNAPSHOT" + const val spigotVersion = "1.13-R0.1-SNAPSHOT" + const val fastutilVersion = "8.5.3" + const val lombokVersion = "1.18.20" + const val guiceVersion = "5.0.1" + const val nettyVersion = "4.1.49.Final" + const val snakeyamlVersion = "1.28" + const val cloudVersion = "1.5.0" + const val adventureApiVersion = "4.9.1" + const val adventurePlatformVersion = "4.0.0" const val javaWebsocketVersion = "1.5.2" diff --git a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java index 8974396f..f01cd64f 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java @@ -37,7 +37,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; -import org.geysermc.cumulus.Form; +import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.util.FormBuilder; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -121,7 +121,7 @@ public boolean sendForm(UUID uuid, Form form) { } @Override - public boolean sendForm(UUID uuid, FormBuilder formBuilder) { + public boolean sendForm(UUID uuid, FormBuilder formBuilder) { return sendForm(uuid, formBuilder.build()); } diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java index 5f546d8e..9d48b732 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java @@ -31,13 +31,16 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; -import org.geysermc.cumulus.Form; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.impl.FormDefinition; +import org.geysermc.cumulus.form.impl.FormDefinitions; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.platform.pluginmessage.PluginMessageUtils; import org.geysermc.floodgate.pluginmessage.PluginMessageChannel; public class FormChannel implements PluginMessageChannel { + private final FormDefinitions formDefinitions = FormDefinitions.instance(); private final Short2ObjectMap
storedForms = new Short2ObjectOpenHashMap<>(); private final AtomicInteger nextFormId = new AtomicInteger(0); @@ -103,10 +106,15 @@ public byte[] createFormData(Form form) { } storedForms.put(formId, form); - byte[] jsonData = form.getJsonData().getBytes(Charsets.UTF_8); + FormDefinition definition = formDefinitions.definitionFor(form); + + byte[] jsonData = + definition.codec() + .jsonData(form) + .getBytes(Charsets.UTF_8); byte[] data = new byte[jsonData.length + 3]; - data[0] = (byte) form.getType().ordinal(); + data[0] = (byte) definition.formType().ordinal(); data[1] = (byte) (formId >> 8 & 0xFF); data[2] = (byte) (formId & 0xFF); System.arraycopy(jsonData, 0, data, 3, jsonData.length); @@ -117,7 +125,12 @@ protected boolean callResponseConsumer(byte[] data) { Form storedForm = storedForms.remove(getFormId(data)); if (storedForm != null) { String responseData = new String(data, 2, data.length - 2, Charsets.UTF_8); - storedForm.getResponseHandler().accept(responseData); + try { + formDefinitions.definitionFor(storedForm) + .handleFormResponse(storedForm, responseData); + } catch (Exception e) { + logger.error("Error while processing form response!", e); + } return true; } return false; From c34970f0b9ad4c376cd07a31ff80f4a04477c04f Mon Sep 17 00:00:00 2001 From: Jackson_57 <49173011+jackson-57@users.noreply.github.com> Date: Sat, 26 Feb 2022 16:48:43 -0500 Subject: [PATCH 002/113] Add obvious download link to the README.md, update wiki links (#171) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5a9d098e..652325ce 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) [![HitCount](https://hits.dwyl.com/GeyserMC/Floodgate.svg)](http://hits.dwyl.com/GeyserMC/Floodgate) +[Download](https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/) + Hybrid mode plugin to allow for connections from [Geyser](https://github.com/GeyserMC/Geyser) to join online mode servers. Geyser is an open collaboration project by [CubeCraft Games](https://cubecraft.net). -See the [Floodgate](https://github.com/GeyserMC/Geyser/wiki/Floodgate) page in the Geyser Wiki for more info about the what Floodgate is, how you setup Floodgate and known issues/caveats. - -See the [Floodgate wiki](https://github.com/GeyserMC/Floodgate/wiki) (currently work in progress) for a more in-depth look into Floodgate, how it works and the Floodgate API. +See the [Floodgate](https://wiki.geysermc.org/floodgate/) section in the GeyserMC Wiki for more info about what Floodgate is, how you setup Floodgate and known issues/caveats. Additionally, it includes a more in-depth look into how Floodgate works and the Floodgate API. From 465e66df7203135c55a45070c25ec0aa13e28070 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 21 Mar 2022 14:41:53 +0100 Subject: [PATCH 003/113] Added metrics and fixed relocations not applying for child projects --- build-logic/src/main/kotlin/extensions.kt | 14 +- .../floodgate.shadow-conventions.gradle.kts | 24 ++- .../module/BungeePlatformModule.java | 7 + .../floodgate/util/BungeePlatformUtils.java | 46 ++++++ core/build.gradle.kts | 1 + .../geysermc/floodgate/FloodgatePlatform.java | 5 +- .../floodgate/command/WhitelistCommand.java | 2 +- .../config/{loader => }/ConfigLoader.java | 4 +- .../floodgate/config/FloodgateConfig.java | 4 +- .../floodgate/module/CommonModule.java | 2 +- .../platform/command/CommandUtil.java | 6 +- .../platform/util/PlatformUtils.java | 37 ++--- .../floodgate/platform/util/PlayerType.java | 32 ++++ .../audience/ProfileAudienceArgument.java | 2 +- .../geysermc/floodgate/util/Constants.java | 2 + .../org/geysermc/floodgate/util/Metrics.java | 143 ++++++++++++++++++ .../module/SpigotPlatformModule.java | 7 + .../geysermc/floodgate/util/ClassNames.java | 17 +++ .../floodgate/util/SpigotPlatformUtils.java | 48 ++++++ velocity/build.gradle.kts | 2 +- .../module/VelocityPlatformModule.java | 3 + .../floodgate/util/VelocityPlatformUtils.java | 46 ++++++ 22 files changed, 406 insertions(+), 48 deletions(-) create mode 100644 bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java rename core/src/main/java/org/geysermc/floodgate/config/{loader => }/ConfigLoader.java (97%) create mode 100644 core/src/main/java/org/geysermc/floodgate/platform/util/PlayerType.java create mode 100644 core/src/main/java/org/geysermc/floodgate/util/Metrics.java create mode 100644 spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java create mode 100644 velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 1b781cb2..a31a492d 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -23,11 +23,9 @@ * @link https://github.com/GeyserMC/Floodgate */ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import net.kyori.indra.git.IndraGitExtension import org.gradle.api.Project import org.gradle.api.artifacts.ProjectDependency -import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.the fun Project.isSnapshot(): Boolean = @@ -54,13 +52,8 @@ fun Project.buildNumber(): Int = fun Project.buildNumberAsString(): String = buildNumber().takeIf { it != -1 }?.toString() ?: "??" -fun Project.relocate(pattern: String) { - tasks.named("shadowJar") { - relocate(pattern, "org.geysermc.floodgate.shaded.$pattern") - } -} - val providedDependencies = mutableMapOf>() +val relocatedPackages = mutableMapOf>() fun Project.provided(pattern: String, name: String, version: String, excludedOn: Int = 0b110) { providedDependencies.getOrPut(project.name) { mutableSetOf() } @@ -73,5 +66,10 @@ fun Project.provided(pattern: String, name: String, version: String, excludedOn: fun Project.provided(dependency: ProjectDependency) = provided(dependency.group!!, dependency.name, dependency.version!!) + +fun Project.relocate(pattern: String) = + relocatedPackages.getOrPut(project.name) { mutableSetOf() } + .add(pattern) + private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String = if (excludedOn and bit > 0) section else "" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts index 5405f480..a0bd500b 100644 --- a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts @@ -24,9 +24,31 @@ tasks { exclude(dependency(string)) } } + + // relocations made in included project dependencies are for whatever reason not + // forwarded to the project implementing the dependency. + // (e.g. a relocation in `core` will relocate for core. But when you include `core` in + // for example Velocity, the relocation will be gone for Velocity) + addRelocations(project, sJar) } } named("build") { dependsOn(shadowJar) } -} \ No newline at end of file +} + +fun addRelocations(project: Project, shadowJar: ShadowJar) { + callAddRelocations(project.configurations.api.get(), shadowJar) + callAddRelocations(project.configurations.implementation.get(), shadowJar) + + relocatedPackages[project.name]?.forEach { pattern -> + println("Relocating $pattern for ${shadowJar.project.name}") + shadowJar.relocate(pattern, "org.geysermc.floodgate.shadow.$pattern") + } +} + +fun callAddRelocations(configuration: Configuration, shadowJar: ShadowJar) = + configuration.dependencies.forEach { + if (it is ProjectDependency) + addRelocations(it.dependencyProject, shadowJar) + } \ No newline at end of file diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java index 7bd1661a..cbe9b5e5 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java +++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java @@ -46,6 +46,7 @@ import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.listener.ListenerRegistration; import org.geysermc.floodgate.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.platform.util.PlatformUtils; import org.geysermc.floodgate.player.FloodgateCommandPreprocessor; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.pluginmessage.BungeePluginMessageRegistration; @@ -55,12 +56,18 @@ import org.geysermc.floodgate.pluginmessage.PluginMessageRegistration; import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.util.BungeeCommandUtil; +import org.geysermc.floodgate.util.BungeePlatformUtils; import org.geysermc.floodgate.util.LanguageManager; @RequiredArgsConstructor public final class BungeePlatformModule extends AbstractModule { private final BungeePlugin plugin; + @Override + protected void configure() { + bind(PlatformUtils.class).to(BungeePlatformUtils.class); + } + @Provides @Singleton public Plugin bungeePlugin() { diff --git a/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java b/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java new file mode 100644 index 00000000..44540da2 --- /dev/null +++ b/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import java.util.List; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.protocol.ProtocolConstants; +import org.geysermc.floodgate.platform.util.PlatformUtils; + +public final class BungeePlatformUtils extends PlatformUtils { + private final ProxyServer proxyServer = ProxyServer.getInstance(); + + @Override + public AuthType authType() { + return proxyServer.getConfig().isOnlineMode() ? AuthType.ONLINE : AuthType.OFFLINE; + } + + @Override + public String minecraftVersion() { + List versions = ProtocolConstants.SUPPORTED_VERSIONS; + return versions.get(versions.size() - 1); + } +} diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 8a1d04e0..adafc1a6 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -26,6 +26,7 @@ relocate("org.bstats") configure { val constantsFile = "src/main/java/org/geysermc/floodgate/util/Constants.java" + replaceToken("\${floodgateVersion}", fullVersion(), constantsFile) replaceToken("\${branch}", branchName(), constantsFile) replaceToken("\${buildNumber}", buildNumber(), constantsFile) } diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index 245ef777..7b963d73 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -40,13 +40,14 @@ import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.packet.PacketHandlers; +import org.geysermc.floodgate.config.ConfigLoader; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfigHolder; -import org.geysermc.floodgate.config.loader.ConfigLoader; import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.module.ConfigLoadedModule; import org.geysermc.floodgate.module.PostInitializeModule; import org.geysermc.floodgate.news.NewsChecker; +import org.geysermc.floodgate.util.Metrics; import org.geysermc.floodgate.util.PrefixCheckTask; public class FloodgatePlatform { @@ -123,6 +124,8 @@ public boolean enable(Module... postInitializeModules) { PrefixCheckTask.checkAndExecuteDelayed(config, logger); + guice.getInstance(Metrics.class); + return true; } diff --git a/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java b/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java index cce707cc..45287f9e 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java @@ -44,7 +44,7 @@ import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.TranslatableMessage; -import org.geysermc.floodgate.platform.util.PlatformUtils.PlayerType; +import org.geysermc.floodgate.platform.util.PlayerType; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.audience.ProfileAudience; import org.geysermc.floodgate.player.audience.ProfileAudienceArgument; diff --git a/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java similarity index 97% rename from core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java rename to core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java index b261e63f..43cbfb3e 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Floodgate */ -package org.geysermc.floodgate.config.loader; +package org.geysermc.floodgate.config; import java.nio.file.Files; import java.nio.file.Path; @@ -36,8 +36,6 @@ import org.geysermc.configutils.file.template.ResourceTemplateReader; import org.geysermc.configutils.updater.change.Changes; import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; diff --git a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java index 9fb105d8..167c40f6 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java +++ b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java @@ -29,11 +29,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.Key; -import java.util.UUID; import lombok.Getter; import org.geysermc.configutils.loader.callback.CallbackResult; import org.geysermc.configutils.loader.callback.GenericPostInitializeCallback; -import org.geysermc.floodgate.config.loader.ConfigLoader; /** * The global Floodgate configuration file used in every platform. Some platforms have their own @@ -99,6 +97,6 @@ public static class PlayerLinkConfig { @Getter public static class MetricsConfig { private boolean enabled; - private UUID uuid; + private String uuid; } } diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 36e8140a..f075bc22 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -40,9 +40,9 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import org.geysermc.floodgate.config.ConfigLoader; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfigHolder; -import org.geysermc.floodgate.config.loader.ConfigLoader; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; diff --git a/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java b/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java index bf9129a1..d159a29e 100644 --- a/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java @@ -25,8 +25,8 @@ package org.geysermc.floodgate.platform.command; -import static org.geysermc.floodgate.platform.util.PlatformUtils.PlayerType.ALL_PLAYERS; -import static org.geysermc.floodgate.platform.util.PlatformUtils.PlayerType.ONLY_BEDROCK; +import static org.geysermc.floodgate.platform.util.PlayerType.ALL_PLAYERS; +import static org.geysermc.floodgate.platform.util.PlayerType.ONLY_BEDROCK; import java.util.ArrayList; import java.util.Collection; @@ -38,7 +38,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.platform.util.PlatformUtils.PlayerType; +import org.geysermc.floodgate.platform.util.PlayerType; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.audience.ProfileAudience; import org.geysermc.floodgate.util.LanguageManager; diff --git a/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java b/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java index 4807c017..81f5096c 100644 --- a/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java @@ -25,37 +25,24 @@ package org.geysermc.floodgate.platform.util; -import java.util.Collection; -import org.geysermc.floodgate.platform.command.CommandUtil; -import org.geysermc.floodgate.platform.command.TranslatableMessage; +import lombok.RequiredArgsConstructor; -public interface PlatformUtils { +@RequiredArgsConstructor +public abstract class PlatformUtils { /** - * Send a message to the specified player, no matter what platform Floodgate is running on. - * - * @param player the player to send the message to - * @param message the command message - * @param locale the locale of the player - * @param args the arguments + * Returns the authentication type used on the platform */ - void sendMessage(Object player, String locale, TranslatableMessage message, Object... args); + public abstract AuthType authType(); /** - * Same as {@link CommandUtil#sendMessage(Object, String, TranslatableMessage, Object...)} except it - * kicks the player. - * - * @param player the player to send the message to - * @param message the command message - * @param locale the locale of the player - * @param args the arguments + * Returns the Minecraft version the server is based on (or the most recent supported version + * for proxy platforms) */ - void kickPlayer(Object player, String locale, TranslatableMessage message, Object... args); + public abstract String minecraftVersion(); - Collection getOnlineUsernames(PlayerType limitTo); - - enum PlayerType { - ALL_PLAYERS, - ONLY_BEDROCK, - ONLY_JAVA + public enum AuthType { + ONLINE, + PROXIED, + OFFLINE } } diff --git a/core/src/main/java/org/geysermc/floodgate/platform/util/PlayerType.java b/core/src/main/java/org/geysermc/floodgate/platform/util/PlayerType.java new file mode 100644 index 00000000..f8c0c97c --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/platform/util/PlayerType.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.platform.util; + +public enum PlayerType { + ALL_PLAYERS, + ONLY_BEDROCK, + ONLY_JAVA +} diff --git a/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java b/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java index d9ed8e47..9c425637 100644 --- a/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java +++ b/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java @@ -37,7 +37,7 @@ import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.platform.command.CommandUtil; -import org.geysermc.floodgate.platform.util.PlatformUtils.PlayerType; +import org.geysermc.floodgate.platform.util.PlayerType; import org.geysermc.floodgate.player.UserAudience; public class ProfileAudienceArgument extends CommandArgument { diff --git a/core/src/main/java/org/geysermc/floodgate/util/Constants.java b/core/src/main/java/org/geysermc/floodgate/util/Constants.java index 86fbc65b..5e97aba3 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Constants.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Constants.java @@ -26,8 +26,10 @@ package org.geysermc.floodgate.util; public final class Constants { + public static final String VERSION = "${floodgateVersion}"; public static final int BUILD_NUMBER = Integer.parseInt("${buildNumber}"); public static final String GIT_BRANCH = "${branch}"; + public static final int METRICS_ID = 14649; public static final char COLOR_CHAR = 'ยง'; diff --git a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java new file mode 100644 index 00000000..50ea1025 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import com.google.inject.Inject; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.inject.Named; +import org.bstats.MetricsBase; +import org.bstats.charts.DrilldownPie; +import org.bstats.charts.SimplePie; +import org.bstats.charts.SingleLineChart; +import org.bstats.json.JsonObjectBuilder; +import org.geysermc.floodgate.api.FloodgateApi; +import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.config.FloodgateConfig; +import org.geysermc.floodgate.config.FloodgateConfig.MetricsConfig; +import org.geysermc.floodgate.platform.util.PlatformUtils; + +public final class Metrics { + private final MetricsBase metricsBase; + + @Inject + Metrics(FloodgateConfig config, PlatformUtils platformUtils, FloodgateApi api, + @Named("implementationName") String implementationName, FloodgateLogger logger) { + + MetricsConfig metricsConfig = config.getMetrics(); + + metricsBase = new MetricsBase( + "server-implementation", + metricsConfig.getUuid(), + Constants.METRICS_ID, + metricsConfig.isEnabled(), + this::appendPlatformData, + jsonObjectBuilder -> { /* NOP */ }, + null, + () -> true, // remove this if/when we add some form of reload support + logger::error, + logger::info, + Constants.DEBUG_MODE, + Constants.DEBUG_MODE, + Constants.DEBUG_MODE + ); + + metricsBase.addCustomChart( + new SingleLineChart("players", api::getPlayerCount) + ); + + metricsBase.addCustomChart( + new DrilldownPie("player_count", () -> { + int playerCount = api.getPlayerCount(); + // 0 = 0 - 4, 9 = 5 - 9, etc. + int category = playerCount / 5 * 5; + String categoryName = category + " - " + (category + 4); + + return Collections.singletonMap( + categoryName, + Collections.singletonMap(implementationName, 1) + ); + }) + ); + + metricsBase.addCustomChart( + new SimplePie("authentication", + () -> platformUtils.authType().name().toLowerCase(Locale.ROOT)) + ); + + metricsBase.addCustomChart( + new SimplePie("floodgate_version", () -> Constants.VERSION) + ); + + metricsBase.addCustomChart(new SimplePie("platform", () -> implementationName)); + + metricsBase.addCustomChart( + new DrilldownPie("minecraft_version", () -> { + // e.g.: 1.16.5 => (Spigot, 1) + return Collections.singletonMap( + platformUtils.minecraftVersion(), + Collections.singletonMap(implementationName, 1) + ); + }) + ); + + // Source: Geyser + metricsBase.addCustomChart(new DrilldownPie("java_version", () -> { + Map> map = new HashMap<>(); + String javaVersion = System.getProperty("java.version"); + Map entry = new HashMap<>(); + entry.put(javaVersion, 1); + + String majorVersion = javaVersion.split("\\.")[0]; + String release; + + int indexOf = javaVersion.lastIndexOf('.'); + + if (majorVersion.equals("1")) { + release = "Java " + javaVersion.substring(0, indexOf); + } else { + Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion); + if (versionMatcher.find()) { + majorVersion = versionMatcher.group(0); + } + release = "Java " + majorVersion; + } + map.put(release, entry); + return map; + })); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } +} diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index 94d8f12a..5547046b 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -42,6 +42,7 @@ import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.listener.ListenerRegistration; import org.geysermc.floodgate.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.platform.util.PlatformUtils; import org.geysermc.floodgate.pluginmessage.PluginMessageRegistration; import org.geysermc.floodgate.pluginmessage.SpigotPluginMessageRegistration; import org.geysermc.floodgate.pluginmessage.SpigotPluginMessageUtils; @@ -49,12 +50,18 @@ import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.SpigotCommandUtil; +import org.geysermc.floodgate.util.SpigotPlatformUtils; import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; @RequiredArgsConstructor public final class SpigotPlatformModule extends AbstractModule { private final SpigotPlugin plugin; + @Override + protected void configure() { + bind(PlatformUtils.class).to(SpigotPlatformUtils.class); + } + @Provides @Singleton public JavaPlugin javaPlugin() { diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 60d38a38..02d93c86 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -58,6 +58,7 @@ public class ClassNames { public static final Field HANDSHAKE_HOST; public static final Field LOGIN_PROFILE; public static final Field PACKET_LISTENER; + @Nullable public static final Field PAPER_DISABLE_USERNAME_VALIDATION; @@ -67,6 +68,10 @@ public class ClassNames { public static final Method INIT_UUID; public static final Method FIRE_LOGIN_EVENTS; + public static final Class SPIGOT_CONFIG; + public static final Field BUNGEE; + public static final Method GET_VERSION; + static { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; SPIGOT_MAPPING_PREFIX = "net.minecraft.server." + version; @@ -162,12 +167,24 @@ public class ClassNames { FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents"); checkNotNull(FIRE_LOGIN_EVENTS, "fireEvents from LoginHandler"); + PAPER_DISABLE_USERNAME_VALIDATION = getField(LOGIN_LISTENER, "iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation"); + if (Constants.DEBUG_MODE) { System.out.println("Paper disable username validation field exists? " + (PAPER_DISABLE_USERNAME_VALIDATION != null)); } + + // SpigotPlatformUtils + SPIGOT_CONFIG = ReflectionUtils.getClass("org.spigotmc.SpigotConfig"); + checkNotNull(SPIGOT_CONFIG, "Spigot config"); + + BUNGEE = ReflectionUtils.getField(SPIGOT_CONFIG, "bungee"); + checkNotNull(BUNGEE, "Bungee field"); + + GET_VERSION = ReflectionUtils.getMethod(MINECRAFT_SERVER, "getVersion"); + checkNotNull(GET_VERSION, "Minecraft server version"); } private static Class getClassOrFallBack(String className, String fallbackName) { diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java new file mode 100644 index 00000000..052334cc --- /dev/null +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import org.bukkit.Bukkit; +import org.geysermc.floodgate.platform.util.PlatformUtils; + +public class SpigotPlatformUtils extends PlatformUtils { + @Override + @SuppressWarnings("ConstantConditions") + public AuthType authType() { + if (Bukkit.getOnlineMode()) { + return AuthType.ONLINE; + } + + boolean bungeeEnabled = ReflectionUtils.getCastedValue(null, ClassNames.BUNGEE); + return bungeeEnabled ? AuthType.PROXIED : AuthType.OFFLINE; + } + + @Override + public String minecraftVersion() { + Object instance = ReflectionUtils.invokeStatic(ClassNames.MINECRAFT_SERVER, "getServer"); + return ReflectionUtils.castedInvoke(instance, ClassNames.GET_VERSION); + } +} diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 5fa61663..2ddcfae5 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -5,7 +5,7 @@ var guavaVersion = "25.1-jre" dependencies { api(projects.core) - api("cloud.commandframework", "cloud-velocity", Versions.cloudVersion) + implementation("cloud.commandframework", "cloud-velocity", Versions.cloudVersion) } relocate("cloud.commandframework") diff --git a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java index 209c07c6..8678af5e 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java +++ b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java @@ -48,6 +48,7 @@ import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.listener.ListenerRegistration; import org.geysermc.floodgate.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.platform.util.PlatformUtils; import org.geysermc.floodgate.player.FloodgateCommandPreprocessor; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; @@ -57,6 +58,7 @@ import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.VelocityCommandUtil; +import org.geysermc.floodgate.util.VelocityPlatformUtils; import org.geysermc.floodgate.util.VelocitySkinApplier; import org.slf4j.Logger; @@ -67,6 +69,7 @@ public final class VelocityPlatformModule extends AbstractModule { @Override protected void configure() { bind(CommandUtil.class).to(VelocityCommandUtil.class); + bind(PlatformUtils.class).to(VelocityPlatformUtils.class); } @Provides diff --git a/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java b/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java new file mode 100644 index 00000000..4abafe61 --- /dev/null +++ b/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import com.google.inject.Inject; +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.proxy.ProxyServer; +import org.geysermc.floodgate.platform.util.PlatformUtils; + +public final class VelocityPlatformUtils extends PlatformUtils { + @Inject + private ProxyServer server; + + @Override + public AuthType authType() { + return server.getConfiguration().isOnlineMode() ? AuthType.ONLINE : AuthType.OFFLINE; + } + + @Override + public String minecraftVersion() { + return ProtocolVersion.MAXIMUM_VERSION.getMostRecentSupportedVersion(); + } +} From 9ff6ad8589faebb9ae512d4cbfc51cadcfa921bd Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 21 Mar 2022 15:14:07 +0100 Subject: [PATCH 004/113] Velocity is also a proxy --- .../geysermc/floodgate/util/ClassNames.java | 23 ++++++++------- .../geysermc/floodgate/util/ProxyUtils.java | 29 ++----------------- .../floodgate/util/SpigotPlatformUtils.java | 8 ++--- 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 02d93c86..66801723 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -59,8 +59,8 @@ public class ClassNames { public static final Field LOGIN_PROFILE; public static final Field PACKET_LISTENER; - @Nullable - public static final Field PAPER_DISABLE_USERNAME_VALIDATION; + @Nullable public static final Field PAPER_DISABLE_USERNAME_VALIDATION; + @Nullable public static final Field PAPER_VELOCITY_SUPPORT; public static final Method GET_PROFILE_METHOD; public static final Method LOGIN_DISCONNECT; @@ -68,9 +68,7 @@ public class ClassNames { public static final Method INIT_UUID; public static final Method FIRE_LOGIN_EVENTS; - public static final Class SPIGOT_CONFIG; public static final Field BUNGEE; - public static final Method GET_VERSION; static { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; @@ -80,7 +78,7 @@ public class ClassNames { // SpigotSkinApplier Class craftPlayerClass = ReflectionUtils.getClass( "org.bukkit.craftbukkit." + version + ".entity.CraftPlayer"); - GET_PROFILE_METHOD = ReflectionUtils.getMethod(craftPlayerClass, "getProfile"); + GET_PROFILE_METHOD = getMethod(craftPlayerClass, "getProfile"); checkNotNull(GET_PROFILE_METHOD, "Get profile method"); String nmsPackage = SPIGOT_MAPPING_PREFIX + '.'; @@ -176,15 +174,18 @@ public class ClassNames { (PAPER_DISABLE_USERNAME_VALIDATION != null)); } - // SpigotPlatformUtils - SPIGOT_CONFIG = ReflectionUtils.getClass("org.spigotmc.SpigotConfig"); - checkNotNull(SPIGOT_CONFIG, "Spigot config"); + // ProxyUtils + Class spigotConfig = ReflectionUtils.getClass("org.spigotmc.SpigotConfig"); + checkNotNull(spigotConfig, "Spigot config"); - BUNGEE = ReflectionUtils.getField(SPIGOT_CONFIG, "bungee"); + BUNGEE = getField(spigotConfig, "bungee"); checkNotNull(BUNGEE, "Bungee field"); - GET_VERSION = ReflectionUtils.getMethod(MINECRAFT_SERVER, "getVersion"); - checkNotNull(GET_VERSION, "Minecraft server version"); + Class paperConfig = ReflectionUtils.getClassSilently( + "com.destroystokyo.paper.PaperConfig"); + + PAPER_VELOCITY_SUPPORT = + paperConfig == null ? null : getField(paperConfig, "velocitySupport"); } private static Class getClassOrFallBack(String className, String fallbackName) { diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java index 55d2bb3d..3080b137 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java @@ -25,45 +25,22 @@ package org.geysermc.floodgate.util; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.geysermc.floodgate.util.ReflectionUtils.getField; - -import java.lang.reflect.Field; - @SuppressWarnings("ConstantConditions") public final class ProxyUtils { - private static final Field IS_BUNGEE_DATA; - private static final Field IS_MODERN_FORWARDING; - - static { - Class spigotConfig = ReflectionUtils.getClass("org.spigotmc.SpigotConfig"); - IS_BUNGEE_DATA = getField(spigotConfig, "bungee"); - checkNotNull(IS_BUNGEE_DATA, "bungee field cannot be null. Are you using CraftBukkit?"); - - Field velocitySupport; - try { - Class paperConfig = Class.forName("com.destroystokyo.paper.PaperConfig"); - velocitySupport = getField(paperConfig, "velocitySupport"); - } catch (ClassNotFoundException e) { - // We're not on a platform that has modern forwarding - velocitySupport = null; // NOPMD - there's really not a better way around this unless you want to use an optional - } - IS_MODERN_FORWARDING = velocitySupport; - } public static boolean isProxyData() { return isBungeeData() || isVelocitySupport(); } private static boolean isBungeeData() { - return ReflectionUtils.getCastedValue(null, IS_BUNGEE_DATA); + return ReflectionUtils.getCastedValue(null, ClassNames.BUNGEE); } private static boolean isVelocitySupport() { - if (IS_MODERN_FORWARDING == null) { + if (ClassNames.PAPER_VELOCITY_SUPPORT == null) { return false; } - return ReflectionUtils.getCastedValue(null, IS_MODERN_FORWARDING); + return ReflectionUtils.getCastedValue(null, ClassNames.PAPER_VELOCITY_SUPPORT); } } \ No newline at end of file diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java index 052334cc..d431bc5b 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java @@ -30,19 +30,15 @@ public class SpigotPlatformUtils extends PlatformUtils { @Override - @SuppressWarnings("ConstantConditions") public AuthType authType() { if (Bukkit.getOnlineMode()) { return AuthType.ONLINE; } - - boolean bungeeEnabled = ReflectionUtils.getCastedValue(null, ClassNames.BUNGEE); - return bungeeEnabled ? AuthType.PROXIED : AuthType.OFFLINE; + return ProxyUtils.isProxyData() ? AuthType.PROXIED : AuthType.OFFLINE; } @Override public String minecraftVersion() { - Object instance = ReflectionUtils.invokeStatic(ClassNames.MINECRAFT_SERVER, "getServer"); - return ReflectionUtils.castedInvoke(instance, ClassNames.GET_VERSION); + return Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0]; } } From 8d52ffd28d10fa4b4de35f0b9c8a47eada6d020b Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 2 Apr 2022 16:21:50 +0200 Subject: [PATCH 005/113] Jenkins uses env variables --- build-logic/src/main/kotlin/extensions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index a31a492d..69368784 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -45,9 +45,9 @@ fun Project.lastCommitHash(): String? = // retrieved from https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project // some properties might be specific to Jenkins fun Project.branchName(): String = - System.getProperty("GIT_BRANCH", "local/dev") + System.getenv("GIT_BRANCH") ?: "local/dev" fun Project.buildNumber(): Int = - Integer.parseInt(System.getProperty("BUILD_NUMBER", "-1")) + Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") fun Project.buildNumberAsString(): String = buildNumber().takeIf { it != -1 }?.toString() ?: "??" From c10561d010a0f9119d412a2ce2525f0e62ba84dc Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 2 Apr 2022 16:27:04 +0200 Subject: [PATCH 006/113] Added platform fork to metrics. Improved MC version detector in Bungee --- .../inject/bungee/BungeeInjector.java | 2 +- .../floodgate/util/BungeePlatformUtils.java | 34 +++++++++++++++++-- .../platform/util/PlatformUtils.java | 2 ++ .../org/geysermc/floodgate/util/Metrics.java | 6 +++- .../floodgate/util/ReflectionUtils.java | 5 +++ .../geysermc/floodgate/util/ProxyUtils.java | 4 +-- .../floodgate/util/SpigotPlatformUtils.java | 5 +++ .../floodgate/util/VelocityPlatformUtils.java | 5 +++ 8 files changed, 57 insertions(+), 6 deletions(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index 4178490b..7181edd2 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -59,7 +59,7 @@ public boolean inject() { // (Instead of just replacing the ChannelInitializer which is only called for // player <-> proxy) BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( - this, ReflectionUtils.getCastedValue(null, framePrepender) + this, ReflectionUtils.castedStaticValue(framePrepender) ); BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender); diff --git a/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java b/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java index 44540da2..fae9a83c 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java +++ b/bungee/src/main/java/org/geysermc/floodgate/util/BungeePlatformUtils.java @@ -25,14 +25,40 @@ package org.geysermc.floodgate.util; +import java.lang.reflect.Field; import java.util.List; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.protocol.ProtocolConstants; import org.geysermc.floodgate.platform.util.PlatformUtils; +@SuppressWarnings("ConstantConditions") public final class BungeePlatformUtils extends PlatformUtils { + private static final String LATEST_SUPPORTED_VERSION; private final ProxyServer proxyServer = ProxyServer.getInstance(); + static { + int protocolNumber = -1; + String versionName = ""; + + for (Field field : ProtocolConstants.class.getFields()) { + if (!field.getName().startsWith("MINECRAFT_")) { + continue; + } + + int fieldValue = ReflectionUtils.castedStaticValue(field); + if (fieldValue > protocolNumber) { + protocolNumber = fieldValue; + versionName = field.getName().substring(10).replace('_', '.'); + } + } + + if (protocolNumber == -1) { + List versions = ProtocolConstants.SUPPORTED_VERSIONS; + versionName = versions.get(versions.size() - 1); + } + LATEST_SUPPORTED_VERSION = versionName; + } + @Override public AuthType authType() { return proxyServer.getConfig().isOnlineMode() ? AuthType.ONLINE : AuthType.OFFLINE; @@ -40,7 +66,11 @@ public AuthType authType() { @Override public String minecraftVersion() { - List versions = ProtocolConstants.SUPPORTED_VERSIONS; - return versions.get(versions.size() - 1); + return LATEST_SUPPORTED_VERSION; + } + + @Override + public String serverImplementationName() { + return proxyServer.getName(); } } diff --git a/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java b/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java index 81f5096c..d9901848 100644 --- a/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/util/PlatformUtils.java @@ -40,6 +40,8 @@ public abstract class PlatformUtils { */ public abstract String minecraftVersion(); + public abstract String serverImplementationName(); + public enum AuthType { ONLINE, PROXIED, diff --git a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java index 50ea1025..be7ff315 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java @@ -96,7 +96,11 @@ public final class Metrics { new SimplePie("floodgate_version", () -> Constants.VERSION) ); - metricsBase.addCustomChart(new SimplePie("platform", () -> implementationName)); + metricsBase.addCustomChart( + new DrilldownPie("platform", () -> Collections.singletonMap( + implementationName, + Collections.singletonMap(platformUtils.serverImplementationName(), 1) + ))); metricsBase.addCustomChart( new DrilldownPie("minecraft_version", () -> { diff --git a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java index 28c5abaf..63605c66 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java @@ -269,6 +269,11 @@ public static T getCastedValue(Object instance, String fieldName) { return (T) getValue(instance, getField(instance.getClass(), fieldName)); } + @Nullable + public static T castedStaticValue(Field field) { + return getCastedValue(null, field); + } + /** * Set the value of a field. This method make the field accessible and then sets the value.
* This method doesn't throw an exception when failed, but it'll log the error to the console. diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java index 3080b137..9d982850 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java @@ -33,7 +33,7 @@ public static boolean isProxyData() { } private static boolean isBungeeData() { - return ReflectionUtils.getCastedValue(null, ClassNames.BUNGEE); + return ReflectionUtils.castedStaticValue(ClassNames.BUNGEE); } private static boolean isVelocitySupport() { @@ -41,6 +41,6 @@ private static boolean isVelocitySupport() { return false; } - return ReflectionUtils.getCastedValue(null, ClassNames.PAPER_VELOCITY_SUPPORT); + return ReflectionUtils.castedStaticValue(ClassNames.PAPER_VELOCITY_SUPPORT); } } \ No newline at end of file diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java index d431bc5b..538c8ce6 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotPlatformUtils.java @@ -41,4 +41,9 @@ public AuthType authType() { public String minecraftVersion() { return Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0]; } + + @Override + public String serverImplementationName() { + return Bukkit.getServer().getName(); + } } diff --git a/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java b/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java index 4abafe61..0340cfac 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java +++ b/velocity/src/main/java/org/geysermc/floodgate/util/VelocityPlatformUtils.java @@ -43,4 +43,9 @@ public AuthType authType() { public String minecraftVersion() { return ProtocolVersion.MAXIMUM_VERSION.getMostRecentSupportedVersion(); } + + @Override + public String serverImplementationName() { + return server.getVersion().getName(); + } } From fc2fe290a6c0494e7c9ea63b36847215a4841428 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 11 May 2022 21:27:41 +0200 Subject: [PATCH 007/113] It should be able to publish now --- .../floodgate.publish-conventions.gradle.kts | 17 ++++++++++------- build.gradle.kts | 2 ++ settings.gradle.kts | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts index 37c815c2..60c3e272 100644 --- a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts @@ -5,24 +5,27 @@ plugins { } publishing { - publications.create("mavenJava") { - groupId = project.group as String - artifactId = "floodgate-" + project.name - version = project.version as String + publications { + create("mavenJava") { + groupId = project.group as String + artifactId = project.name + version = project.version as String - artifact(tasks["shadowJar"]) - artifact(tasks["sourcesJar"]) + artifact(tasks["shadowJar"]) + artifact(tasks["sourcesJar"]) + } } } artifactory { + setContextUrl("https://repo.opencollab.dev/artifactory") publish { repository { setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases") setMavenCompatible(true) } defaults { - publishConfigs("archives") + publications("mavenJava") setPublishArtifacts(true) setPublishPom(true) setPublishIvy(false) diff --git a/build.gradle.kts b/build.gradle.kts index b24fcbfa..6b08cf0b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,6 +18,8 @@ val platforms = setOf( projects.velocity ).map { it.dependencyProject } +projects.api.dependencyProject.plugins.apply("floodgate.publish-conventions") + //todo re-add pmd and organisation/license/sdcm/issuemanagement stuff subprojects { diff --git a/settings.gradle.kts b/settings.gradle.kts index 11653aab..7df9d09c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,8 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { +// mavenLocal() + // Geyser, Cumulus etc. maven("https://repo.opencollab.dev/maven-releases") { mavenContent { releasesOnly() } From b85ba07edd0c2f08f0666210e1984995065bb31b Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 11 May 2022 22:57:34 +0200 Subject: [PATCH 008/113] Don't archive core & api artifacts. Don't deploy databases. Deploy core --- Jenkinsfile | 5 ++++- .../floodgate.database-conventions.gradle.kts | 2 +- build.gradle.kts | 17 +++++++++-------- core/build.gradle.kts | 1 - 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0f9cf367..cfaa560d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -21,7 +21,10 @@ pipeline { post { success { archiveArtifacts artifacts: '**/build/libs/floodgate-*.jar', - excludes: '**/floodgate-parent-*.jar', + excludes: + '**/floodgate-parent-*.jar', + '**/floodgate-api-*.jar', + '**/floodgate-core-*.jar' fingerprint: true } } diff --git a/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts index b41417e2..2012ba65 100644 --- a/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("floodgate.publish-conventions") + id("floodgate.shadow-conventions") } tasks { diff --git a/build.gradle.kts b/build.gradle.kts index 6b08cf0b..c0652297 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,14 +12,15 @@ allprojects { description = "Allows Bedrock players to join Java edition servers while keeping the server in online mode" } -val platforms = setOf( +val deployProjects = setOf( + projects.api, + // for future Floodgate integration + Fabric + projects.core, projects.bungee, projects.spigot, projects.velocity ).map { it.dependencyProject } -projects.api.dependencyProject.plugins.apply("floodgate.publish-conventions") - //todo re-add pmd and organisation/license/sdcm/issuemanagement stuff subprojects { @@ -44,10 +45,10 @@ subprojects { if (relativePath.startsWith("database" + File.separator)) { group = rootProject.group as String + ".database" plugins.apply("floodgate.database-conventions") - } else { - when (this) { - in platforms -> plugins.apply("floodgate.publish-conventions") - else -> plugins.apply("floodgate.base-conventions") - } + } + + when (this) { + in deployProjects -> plugins.apply("floodgate.publish-conventions") + else -> plugins.apply("floodgate.base-conventions") } } \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index adafc1a6..02fec9dd 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -2,7 +2,6 @@ import net.kyori.blossom.BlossomExtension plugins { id("net.kyori.blossom") - id("floodgate.shadow-conventions") } dependencies { From d0b3a38af5c46dbb1793637fe93591c83cbcc6e8 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 11 May 2022 23:05:00 +0200 Subject: [PATCH 009/113] Jenkins change your syntax pls --- Jenkinsfile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index cfaa560d..4ba07e64 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -21,10 +21,7 @@ pipeline { post { success { archiveArtifacts artifacts: '**/build/libs/floodgate-*.jar', - excludes: - '**/floodgate-parent-*.jar', - '**/floodgate-api-*.jar', - '**/floodgate-core-*.jar' + excludes: '**/floodgate-parent-*.jar,**/floodgate-api-*.jar,**/floodgate-core-*.jar', fingerprint: true } } From 5034c5f5a9025aeaf425f90eed735bbf1ac58a4d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 11 May 2022 23:11:53 +0200 Subject: [PATCH 010/113] Use the correct jar names --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4ba07e64..80976be7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -21,7 +21,7 @@ pipeline { post { success { archiveArtifacts artifacts: '**/build/libs/floodgate-*.jar', - excludes: '**/floodgate-parent-*.jar,**/floodgate-api-*.jar,**/floodgate-core-*.jar', + excludes: '**/floodgate-parent-*.jar,**/floodgate-api.jar,**/floodgate-core.jar', fingerprint: true } } From b2d2efcedd33fe6a9cba38d7e1b6f28316286566 Mon Sep 17 00:00:00 2001 From: Hugo Planque <12386279+HookWoods@users.noreply.github.com> Date: Sun, 15 May 2022 23:18:49 +0200 Subject: [PATCH 011/113] Return the value of optional and not the optional itself (#301) --- .../java/org/geysermc/floodgate/util/VelocityCommandUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/velocity/src/main/java/org/geysermc/floodgate/util/VelocityCommandUtil.java b/velocity/src/main/java/org/geysermc/floodgate/util/VelocityCommandUtil.java index 8edf09da..a2c355f3 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/util/VelocityCommandUtil.java +++ b/velocity/src/main/java/org/geysermc/floodgate/util/VelocityCommandUtil.java @@ -90,13 +90,13 @@ protected Collection getOnlinePlayers() { @Override public Object getPlayerByUuid(@NonNull UUID uuid) { Optional player = server.getPlayer(uuid); - return player.isPresent() ? player : uuid; + return player.isPresent() ? player.get() : uuid; } @Override public Object getPlayerByUsername(@NonNull String username) { Optional player = server.getPlayer(username); - return player.isPresent() ? player : username; + return player.isPresent() ? player.get() : username; } @Override From dbf2471eff5d1362c3e7f9a396d3ae37d9c507cf Mon Sep 17 00:00:00 2001 From: Hugo Planque <12386279+HookWoods@users.noreply.github.com> Date: Sun, 15 May 2022 23:19:45 +0200 Subject: [PATCH 012/113] Fix floodgate not loading with mongo when collection already exists (#300) --- .../org/geysermc/floodgate/database/MongoDbDatabase.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/database/mongo/src/main/java/org/geysermc/floodgate/database/MongoDbDatabase.java b/database/mongo/src/main/java/org/geysermc/floodgate/database/MongoDbDatabase.java index 1f1d6eb8..19f9058b 100644 --- a/database/mongo/src/main/java/org/geysermc/floodgate/database/MongoDbDatabase.java +++ b/database/mongo/src/main/java/org/geysermc/floodgate/database/MongoDbDatabase.java @@ -40,6 +40,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.time.Instant; +import java.util.ArrayList; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -336,12 +337,7 @@ private UUID bytesToUUID(String uuidBytes) { } public boolean collectionNotExists(final String collectionName) { - try (MongoCursor collectionNames = database.listCollectionNames().cursor()) { - if (collectionNames.hasNext() && collectionNames.next().equals(collectionName)) { - return false; - } - } - return true; + return !database.listCollectionNames().into(new ArrayList<>()).contains(collectionName); } } From f2ebf0b6ebb5d173c3c74c111e28b68da239e2a0 Mon Sep 17 00:00:00 2001 From: Hugo Planque <12386279+HookWoods@users.noreply.github.com> Date: Sun, 15 May 2022 23:27:18 +0200 Subject: [PATCH 013/113] Use ProfileAudience instead. It's a ProfileAudienceArgument (#302) --- .../org/geysermc/floodgate/command/LinkAccountCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java b/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java index 60392de7..4f51c51c 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java @@ -46,6 +46,7 @@ import org.geysermc.floodgate.platform.command.TranslatableMessage; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience.PlayerAudience; +import org.geysermc.floodgate.player.audience.ProfileAudience; import org.geysermc.floodgate.player.audience.ProfileAudienceArgument; import org.geysermc.floodgate.util.Constants; @@ -136,7 +137,7 @@ public void execute(CommandContext context) { return; } - UserAudience targetUser = context.get("player"); + ProfileAudience targetUser = context.get("player"); String targetName = targetUser.username(); link.createLinkRequest(sender.uuid(), sender.username(), targetName) From 523f28d29a2c2df58a001ea053a087d35f1f37c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Br=C3=A4mer?= Date: Sun, 15 May 2022 22:49:03 +0100 Subject: [PATCH 014/113] Fix typos (#273) * Fix typos * Fix another typo * Fix error log message (GeyserMC/Floodgate#275) Co-authored-by: Tim203 --- .../java/org/geysermc/floodgate/api/inject/InjectorAddon.java | 4 ++-- .../org/geysermc/floodgate/inject/CommonPlatformInjector.java | 2 +- .../geysermc/floodgate/inject/velocity/VelocityInjector.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java b/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java index d550cbcb..ee991b78 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java +++ b/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java @@ -34,7 +34,7 @@ public interface InjectorAddon { * used for third party things. * * @param channel the channel that the injector is injecting - * @param toServer if the the connection is between a proxy and a server + * @param toServer if the connection is between a proxy and a server */ void onInject(Channel channel, boolean toServer); @@ -43,7 +43,7 @@ public interface InjectorAddon { * closed connection (if it is injected), so it'll also run this method for closed connections * between a server and the proxy (when Floodgate is running on a proxy). * - * @param channel the channel that the injecor injected + * @param channel the channel that the injector injected */ default void onChannelClosed(Channel channel) { } diff --git a/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java b/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java index 48449372..9025ca0d 100644 --- a/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java +++ b/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java @@ -77,7 +77,7 @@ public void injectAddonsCall(Channel channel, boolean proxyToServer) { } /** - * Method to loop throguh all the addons and call {@link InjectorAddon#onChannelClosed(Channel)} + * Method to loop through all the addons and call {@link InjectorAddon#onChannelClosed(Channel)} * if {@link InjectorAddon#shouldInject()} * * @param channel the channel that was injected diff --git a/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java b/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java index a37768bb..1a4d43b1 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java +++ b/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java @@ -82,7 +82,7 @@ public boolean canRemoveInjection() { @Override public boolean removeInjection() { - logger.error("Floodgate cannot remove itself from Bungee without a reboot"); + logger.error("Floodgate cannot remove itself from Velocity without a reboot"); return false; } From e6bf250a1dd126e6d8d4c9f5fa113ff99e2907a4 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 27 May 2022 18:24:40 +0200 Subject: [PATCH 015/113] Fixes #303 and changed some metrics --- .../geysermc/floodgate/command/LinkAccountCommand.java | 9 ++++----- .../main/java/org/geysermc/floodgate/util/Metrics.java | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java b/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java index 4f51c51c..fe8695fd 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java @@ -90,6 +90,10 @@ public void execute(CommandContext context) { return; } + ProfileAudience targetUser = context.get("player"); + // allowUuid is false so username cannot be null + String targetName = targetUser.username(); + // when the player is a Bedrock player if (api.isFloodgatePlayer(sender.uuid())) { if (!context.contains("code")) { @@ -97,8 +101,6 @@ public void execute(CommandContext context) { return; } - UserAudience targetUser = context.get("player"); - String targetName = targetUser.username(); String code = context.get("code"); link.verifyLinkRequest(sender.uuid(), targetName, sender.username(), code) @@ -137,9 +139,6 @@ public void execute(CommandContext context) { return; } - ProfileAudience targetUser = context.get("player"); - String targetName = targetUser.username(); - link.createLinkRequest(sender.uuid(), sender.username(), targetName) .whenComplete((result, throwable) -> { if (throwable != null || result == LinkRequestResult.UNKNOWN_ERROR) { diff --git a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java index be7ff315..008d215e 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java @@ -81,8 +81,8 @@ public final class Metrics { String categoryName = category + " - " + (category + 4); return Collections.singletonMap( - categoryName, - Collections.singletonMap(implementationName, 1) + implementationName, + Collections.singletonMap(categoryName, 1) ); }) ); @@ -106,8 +106,8 @@ public final class Metrics { new DrilldownPie("minecraft_version", () -> { // e.g.: 1.16.5 => (Spigot, 1) return Collections.singletonMap( - platformUtils.minecraftVersion(), - Collections.singletonMap(implementationName, 1) + implementationName, + Collections.singletonMap(platformUtils.minecraftVersion(), 1) ); }) ); From e824d0f4d17d2ab94679d055ff75659d3a8e9584 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 6 Jun 2022 11:16:11 +0200 Subject: [PATCH 016/113] Re-added the old sendForm methods --- .../geysermc/floodgate/api/FloodgateApi.java | 26 ++++++++++++---- .../floodgate/api/player/FloodgatePlayer.java | 30 +++++++++++++++---- build-logic/src/main/kotlin/Versions.kt | 4 +-- .../floodgate/api/SimpleFloodgateApi.java | 12 +++++++- 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java index 38f368d8..0d2b0efd 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java +++ b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java @@ -29,7 +29,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.util.FormBuilder; +import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.unsafe.Unsafe; @@ -84,8 +84,8 @@ static FloodgateApi getInstance() { /** * Checks if the uuid of the player has the {@link #createJavaPlayerId(long)} format. This - * method can't validate a linked player uuid, since that doesn't equal the format. Use {@link - * #isFloodgatePlayer(UUID)} if you want to include linked accounts. + * method can't validate a linked player uuid, since that doesn't equal the format. Use + * {@link #isFloodgatePlayer(UUID)} if you want to include linked accounts. * * @param uuid the uuid to check * @return true if the given uuid has the correct format. @@ -96,6 +96,20 @@ static FloodgateApi getInstance() { boolean sendForm(UUID uuid, FormBuilder formBuilder); + /** + * @deprecated since Cumulus 1.1 and will be removed when Cumulus 2.0 releases. Please use the + * new form classes instead. + */ + @Deprecated + boolean sendForm(UUID uuid, org.geysermc.cumulus.Form form); + + /** + * @deprecated since Cumulus 1.1 and will be removed when Cumulus 2.0 releases. Please use the + * new form classes instead. + */ + @Deprecated + boolean sendForm(UUID uuid, org.geysermc.cumulus.util.FormBuilder formBuilder); + boolean transferPlayer(UUID uuid, String address, int port); /** @@ -108,9 +122,9 @@ static FloodgateApi getInstance() { CompletableFuture getXuidFor(String gamertag); /** - * Get the xuid of the player that has the given gamertag. It does the same thing as {@link - * #getXuidFor(String)} except that this method will return the xuid in Floodgate uuid format - * instead of just a long + * Get the xuid of the player that has the given gamertag. It does the same thing as + * {@link #getXuidFor(String)} except that this method will return the xuid in Floodgate uuid + * format instead of just a long * * @param gamertag the gamertag of the player * @return the xuid of the player with the given gamertag, or null when there is no player with diff --git a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java index 584e2943..c69578c5 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java +++ b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java @@ -27,7 +27,7 @@ import java.util.UUID; import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.util.FormBuilder; +import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.util.DeviceOs; import org.geysermc.floodgate.util.InputMode; @@ -49,14 +49,16 @@ public interface FloodgatePlayer { UUID getJavaUniqueId(); /** - * Returns the uuid that the server will use as uuid of that player. Will return {@link - * #getJavaUniqueId()} when not linked or {@link LinkedPlayer#getJavaUniqueId()} when linked. + * Returns the uuid that the server will use as uuid of that player. Will return + * {@link #getJavaUniqueId()} when not linked or {@link LinkedPlayer#getJavaUniqueId()} when + * linked. */ UUID getCorrectUniqueId(); /** - * Returns the username the server will as username for that player. Will return {@link - * #getJavaUsername()} when not linked or {@link LinkedPlayer#getJavaUsername()} when linked. + * Returns the username the server will as username for that player. Will return + * {@link #getJavaUsername()} when not linked or {@link LinkedPlayer#getJavaUsername()} when + * linked. */ String getCorrectUsername(); @@ -119,6 +121,24 @@ default boolean sendForm(FormBuilder formBuilder) { return sendForm(formBuilder.build()); } + /** + * @deprecated since Cumulus 1.1 and will be removed when Cumulus 2.0 releases. Please use the + * new form classes instead. + */ + @Deprecated + default boolean sendForm(org.geysermc.cumulus.Form form) { + return sendForm(form.newForm()); + } + + /** + * @deprecated since Cumulus 1.1 and will be removed when Cumulus 2.0 releases. Please use the + * new form classes instead. + */ + @Deprecated + default boolean sendForm(org.geysermc.cumulus.util.FormBuilder formBuilder) { + return sendForm(formBuilder.build()); + } + default boolean transfer(String address, int port) { return FloodgateApi.getInstance().transferPlayer(getCorrectUniqueId(), address, port); } diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 34392cfa..97c16186 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,10 +24,10 @@ */ object Versions { - const val geyserVersion = "2.0.1-cumulus-SNAPSHOT" + const val geyserVersion = "2.0.3-cumulus-SNAPSHOT" const val cumulusVersion = "1.1-SNAPSHOT" const val configUtilsVersion = "1.0-SNAPSHOT" - const valspigotVersion = "1.13-R0.1-SNAPSHOT" + const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" const val lombokVersion = "1.18.20" const val guiceVersion = "5.0.1" diff --git a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java index f01cd64f..94db6743 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java @@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.util.FormBuilder; +import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.unsafe.Unsafe; @@ -125,6 +125,16 @@ public boolean sendForm(UUID uuid, FormBuilder formBuilder) { return sendForm(uuid, formBuilder.build()); } + @Override + public boolean sendForm(UUID uuid, org.geysermc.cumulus.Form form) { + return sendForm(uuid, form.newForm()); + } + + @Override + public boolean sendForm(UUID uuid, org.geysermc.cumulus.util.FormBuilder formBuilder) { + return sendForm(uuid, formBuilder.build()); + } + @Override public boolean transferPlayer(UUID uuid, String address, int port) { return pluginMessageManager From 78254df1de63f33439dbadaa57333d787cc25784 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 7 Jun 2022 00:33:03 +0200 Subject: [PATCH 017/113] Use release version of Cumulus 1.1 --- build-logic/src/main/kotlin/Versions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 97c16186..c4d78a22 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,8 +24,8 @@ */ object Versions { - const val geyserVersion = "2.0.3-cumulus-SNAPSHOT" - const val cumulusVersion = "1.1-SNAPSHOT" + const val geyserVersion = "2.0.3-SNAPSHOT" + const val cumulusVersion = "1.1" const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" From d68c9d6055c8a9d6aa0dd1f2750f32db8e9cffc5 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 7 Jun 2022 23:08:16 +0200 Subject: [PATCH 018/113] Bump version to 2.2 --- Jenkinsfile | 2 +- build.gradle.kts | 17 +++-------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 80976be7..b52cca93 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -31,7 +31,7 @@ pipeline { when { anyOf { branch "master" - branch "dev/2.1.1" + branch "development" } } diff --git a/build.gradle.kts b/build.gradle.kts index c0652297..b64f35aa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,12 @@ plugins { `java-library` id("floodgate.build-logic") -// id("com.github.spotbugs") version "4.8.0" apply false id("io.freefair.lombok") version "6.3.0" apply false -// checkstyle } allprojects { group = "org.geysermc.floodgate" - version = "2.1.1-SNAPSHOT" + version = "2.2.0-SNAPSHOT" description = "Allows Bedrock players to join Java edition servers while keeping the server in online mode" } @@ -21,25 +19,16 @@ val deployProjects = setOf( projects.velocity ).map { it.dependencyProject } -//todo re-add pmd and organisation/license/sdcm/issuemanagement stuff +//todo re-add checkstyle when we switch back to 2 space indention +// and take a look again at spotbugs someday subprojects { -// apply(plugin = "com.github.spotbugs") - apply { plugin("java-library") -// plugin("checkstyle") plugin("io.freefair.lombok") plugin("floodgate.build-logic") } -// checkstyle { -// toolVersion = "9.3" -// configFile = rootProject.projectDir.resolve("checkstyle.xml") -// maxErrors = 0 -// maxWarnings = 0 -// } - val relativePath = projectDir.relativeTo(rootProject.projectDir).path if (relativePath.startsWith("database" + File.separator)) { From 1eec00606c82842f22610e15108a3b9ff8c67a33 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 8 Jun 2022 00:08:39 +0200 Subject: [PATCH 019/113] Fixed building --- build-logic/src/main/kotlin/Versions.kt | 2 +- build-logic/src/main/kotlin/extensions.kt | 18 +++++++++++------- .../floodgate.shadow-conventions.gradle.kts | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index c4d78a22..dca638e6 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,7 +24,7 @@ */ object Versions { - const val geyserVersion = "2.0.3-SNAPSHOT" + const val geyserVersion = "2.0.4-SNAPSHOT" const val cumulusVersion = "1.1" const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 69368784..54158d84 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -52,19 +52,23 @@ fun Project.buildNumber(): Int = fun Project.buildNumberAsString(): String = buildNumber().takeIf { it != -1 }?.toString() ?: "??" -val providedDependencies = mutableMapOf>() +val providedDependencies = mutableMapOf>>() val relocatedPackages = mutableMapOf>() fun Project.provided(pattern: String, name: String, version: String, excludedOn: Int = 0b110) { - providedDependencies.getOrPut(project.name) { mutableSetOf() } - .add("${calcExclusion(pattern, 0b100, excludedOn)}:" + - "${calcExclusion(name, 0b10, excludedOn)}:" + - calcExclusion(version, 0b1, excludedOn)) + val format = "${calcExclusion(pattern, 0b100, excludedOn)}:" + + "${calcExclusion(name, 0b10, excludedOn)}:" + + calcExclusion(version, 0b1, excludedOn) + + providedDependencies.getOrPut(project.name) { mutableSetOf() }.add(Pair(format, format)) dependencies.add("compileOnlyApi", "$pattern:$name:$version") } -fun Project.provided(dependency: ProjectDependency) = - provided(dependency.group!!, dependency.name, dependency.version!!) +fun Project.provided(dependency: ProjectDependency) { + providedDependencies.getOrPut(project.name) { mutableSetOf() } + .add(Pair(dependency.group + ":" + dependency.name, dependency)) + dependencies.add("compileOnlyApi", dependency) +} fun Project.relocate(pattern: String) = diff --git a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts index a0bd500b..bf3de089 100644 --- a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts @@ -18,10 +18,10 @@ tasks { val sJar: ShadowJar = this doFirst { - providedDependencies[project.name]?.forEach { string -> + providedDependencies[project.name]?.forEach { (name, notation) -> sJar.dependencies { - println("Excluding $string from ${project.name}") - exclude(dependency(string)) + println("Excluding $name from ${project.name}") + exclude(dependency(notation)) } } From 5d5713ed9e9eeab0f4abdaa9cf5cd8619dc1909b Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 8 Jun 2022 21:50:51 +0200 Subject: [PATCH 020/113] Fixed BungeeCord 1.19 support Since everyone generally updates their proxy this doesn't provide backwards compatibility with BungeeCord versions that don't support 1.19 clients. --- bungee/build.gradle.kts | 2 +- .../geysermc/floodgate/pluginmessage/BungeeSkinApplier.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index b362a0ac..316e91ed 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -1,4 +1,4 @@ -var bungeeCommit = "bda1605" +var bungeeCommit = "ff5727c" var gsonVersion = "2.8.0" var guavaVersion = "21.0" diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index 3a10b764..35e19bd2 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -34,7 +34,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.connection.LoginResult; -import net.md_5.bungee.connection.LoginResult.Property; +import net.md_5.bungee.protocol.Property; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.skin.SkinApplier; @@ -47,7 +47,7 @@ public final class BungeeSkinApplier implements SkinApplier { static { LOGIN_RESULT = getFieldOfType(InitialHandler.class, LoginResult.class); } - + private final FloodgateLogger logger; @Override From af4030ac12380ecf1bd517a279f34970e9d513d0 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 11 Jun 2022 14:12:13 +0200 Subject: [PATCH 021/113] Re-added support for BungeeCord 1.18 Metrics showed that more than 33% of the BungeeCord platform users still use a 1.18.x version --- build-logic/src/main/kotlin/Versions.kt | 1 - .../pluginmessage/BungeeSkinApplier.java | 41 +++++++++++++++---- .../floodgate/util/ReflectionUtils.java | 30 +++++++++++++- .../geysermc/floodgate/util/ClassNames.java | 36 ++++------------ 4 files changed, 71 insertions(+), 37 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index dca638e6..740288d8 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -29,7 +29,6 @@ object Versions { const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" - const val lombokVersion = "1.18.20" const val guiceVersion = "5.0.1" const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index 35e19bd2..ee10c47a 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -25,27 +25,48 @@ package org.geysermc.floodgate.pluginmessage; +import static com.google.common.base.Preconditions.checkNotNull; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; -import static org.geysermc.floodgate.util.ReflectionUtils.setValue; +import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.Method; import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.connection.LoginResult; -import net.md_5.bungee.protocol.Property; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.floodgate.util.ReflectionUtils; @RequiredArgsConstructor public final class BungeeSkinApplier implements SkinApplier { - private static final Field LOGIN_RESULT; + private static final Field LOGIN_RESULT_FIELD; + private static final Method SET_PROPERTIES_METHOD; + + private static final Class PROPERTY_CLASS; + private static final Constructor PROPERTY_CONSTRUCTOR; static { - LOGIN_RESULT = getFieldOfType(InitialHandler.class, LoginResult.class); + LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class); + checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null"); + + SET_PROPERTIES_METHOD = getMethodByName(LoginResult.class, "setProperties", true); + + PROPERTY_CLASS = ReflectionUtils.getClassOrFallbackPrefixed( + "protocol.Property", "connection.LoginResult.Property" + ); + + PROPERTY_CONSTRUCTOR = ReflectionUtils.getConstructor( + PROPERTY_CLASS, true, + String.class, String.class, String.class + ); + checkNotNull(PROPERTY_CONSTRUCTOR, "Property constructor cannot be null"); } private final FloodgateLogger logger; @@ -71,11 +92,17 @@ public void applySkin(FloodgatePlayer uuid, SkinData skinData) { if (loginResult == null) { // id and name are unused and properties will be overridden loginResult = new LoginResult(null, null, null); - setValue(handler, LOGIN_RESULT, loginResult); + ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult); } - Property property = new Property("textures", skinData.getValue(), skinData.getSignature()); + Object property = ReflectionUtils.newInstance( + PROPERTY_CONSTRUCTOR, + "textures", skinData.getValue(), skinData.getSignature() + ); + + Object propertyArray = Array.newInstance(PROPERTY_CLASS, 1); + Array.set(propertyArray, 0, property); - loginResult.setProperties(new Property[]{property}); + ReflectionUtils.invoke(loginResult, SET_PROPERTIES_METHOD, propertyArray); } } diff --git a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java index 63605c66..32596344 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java @@ -46,6 +46,10 @@ public final class ReflectionUtils { @Setter private static String prefix; + private static String applyPrefix(String className) { + return prefix + "." + className; + } + /** * Get a class that is prefixed with the prefix provided in {@link #setPrefix(String)}. Calling * this method is equal to calling {@link #getClass(String)} with prefix.classname @@ -56,13 +60,13 @@ public final class ReflectionUtils { */ @Nullable public static Class getPrefixedClass(String className) { - return getClass(prefix + "." + className); + return getClass(applyPrefix(className)); } @Nullable public static Class getPrefixedClassSilently(String className) { try { - return Class.forName(prefix + "." + className); + return Class.forName(applyPrefix(className)); } catch (ClassNotFoundException ignored) { return null; } @@ -109,6 +113,28 @@ public static Class getClassOrThrow(String className) { } } + public static Class getClassOrFallbackPrefixed(String className, String fallbackClassName) { + return getClassOrFallback(applyPrefix(className), applyPrefix(fallbackClassName)); + } + + public static Class getClassOrFallback(String className, String fallbackClassName) { + Class clazz = getClassSilently(className); + + if (clazz != null) { + if (Constants.DEBUG_MODE) { + System.out.println("Found class (primary): " + clazz.getName()); + } + return clazz; + } + + // do throw an exception when both classes couldn't be found + clazz = ReflectionUtils.getClassOrThrow(fallbackClassName); + if (Constants.DEBUG_MODE) { + System.out.println("Found class (fallback): " + clazz.getName()); + } + return clazz; + } + @Nullable public static Constructor getConstructor(Class clazz, boolean declared, Class... parameters) { try { diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 66801723..4d0908e7 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -25,6 +25,7 @@ package org.geysermc.floodgate.util; +import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallback; import static org.geysermc.floodgate.util.ReflectionUtils.getField; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; import static org.geysermc.floodgate.util.ReflectionUtils.getMethod; @@ -85,12 +86,12 @@ public class ClassNames { // SpigotInjector - MINECRAFT_SERVER = getClassOrFallBack( + MINECRAFT_SERVER = getClassOrFallback( "net.minecraft.server.MinecraftServer", nmsPackage + "MinecraftServer" ); - SERVER_CONNECTION = getClassOrFallBack( + SERVER_CONNECTION = getClassOrFallback( "net.minecraft.server.network.ServerConnection", nmsPackage + "ServerConnection" ); @@ -105,14 +106,14 @@ public class ClassNames { craftOfflinePlayerClass, true, craftServerClass, GameProfile.class); // SpigotDataHandler - Class networkManager = getClassOrFallBack( + Class networkManager = getClassOrFallback( "net.minecraft.network.NetworkManager", nmsPackage + "NetworkManager" ); SOCKET_ADDRESS = getFieldOfType(networkManager, SocketAddress.class, false); - HANDSHAKE_PACKET = getClassOrFallBack( + HANDSHAKE_PACKET = getClassOrFallback( "net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol", nmsPackage + "PacketHandshakingInSetProtocol" ); @@ -120,12 +121,12 @@ public class ClassNames { HANDSHAKE_HOST = getFieldOfType(HANDSHAKE_PACKET, String.class); checkNotNull(HANDSHAKE_HOST, "Handshake host"); - LOGIN_START_PACKET = getClassOrFallBack( + LOGIN_START_PACKET = getClassOrFallback( "net.minecraft.network.protocol.login.PacketLoginInStart", nmsPackage + "PacketLoginInStart" ); - LOGIN_LISTENER = getClassOrFallBack( + LOGIN_LISTENER = getClassOrFallback( "net.minecraft.server.network.LoginListener", nmsPackage + "LoginListener" ); @@ -146,14 +147,14 @@ public class ClassNames { INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID"); checkNotNull(INIT_UUID, "initUUID from LoginListener"); - Class packetListenerClass = getClassOrFallBack( + Class packetListenerClass = getClassOrFallback( "net.minecraft.network.PacketListener", nmsPackage + "PacketListener" ); PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass); checkNotNull(PACKET_LISTENER, "Packet listener"); - LOGIN_HANDLER = getClassOrFallBack( + LOGIN_HANDLER = getClassOrFallback( "net.minecraft.server.network.LoginListener$LoginHandler", nmsPackage + "LoginListener$LoginHandler" ); @@ -188,25 +189,6 @@ public class ClassNames { paperConfig == null ? null : getField(paperConfig, "velocitySupport"); } - private static Class getClassOrFallBack(String className, String fallbackName) { - Class clazz = ReflectionUtils.getClassSilently(className); - - if (clazz != null) { - if (Constants.DEBUG_MODE) { - System.out.println("Found class (primary): " + clazz.getName()); - } - return clazz; - } - - // do throw an exception when both classes couldn't be found - clazz = ReflectionUtils.getClassOrThrow(fallbackName); - if (Constants.DEBUG_MODE) { - System.out.println("Found class (fallback): " + clazz.getName()); - } - - return clazz; - } - private static void checkNotNull(Object toCheck, String objectName) { Preconditions.checkNotNull(toCheck, objectName + " cannot be null"); } From 59b37f20e40391a878ca870c394d612fbcf66298 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 11 Jun 2022 14:58:15 +0200 Subject: [PATCH 022/113] Disable key encryption requirement for Floodgate Velocity players --- .../floodgate/util/ReflectionUtils.java | 10 ++--- .../addon/data/VelocityProxyDataHandler.java | 42 ++++++++++++++++++- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java index 32596344..13d16d8a 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java @@ -169,7 +169,7 @@ public static T newInstance(Constructor constructor, Object... parameters * * @param clazz the class name to get the field from * @param fieldName the name of the field - * @param declared if the field is declared or public. + * @param declared if the field is declared. * @return the field if found, otherwise null */ @Nullable @@ -206,7 +206,7 @@ public static Field getField(Class clazz, String fieldName) { * * @param clazz the class to search the field from * @param fieldType the type of the field - * @param declared if the field is declared or public + * @param declared if the field is declared * @return the field if it has been found, otherwise null */ @Nullable @@ -342,7 +342,7 @@ public static boolean setValue(Object instance, String fieldName, Object value) * * @param clazz the class to get the method from * @param method the name of the method to find - * @param declared if the the method is declared or public + * @param declared if the the method is declared * @param arguments the classes of the method arguments * @return the requested method if it has been found, otherwise null */ @@ -427,7 +427,7 @@ public static Method getMethod( * * @param clazz the class to search the method in * @param methodName the name of the method - * @param declared if the method is declared or public + * @param declared if the method is declared * @return the method if it has been found, otherwise null */ @Nullable @@ -446,7 +446,7 @@ public static Method getMethodByName(Class clazz, String methodName, boolean * * @param clazz the class to search the method in * @param paramType the type of one of the method parameters - * @param declared if the method is declared or public + * @param declared if the method is declared * @return the method if it has been found, otherwise null */ @Nullable diff --git a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java index a19b71ed..a623fdaf 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java +++ b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java @@ -28,12 +28,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue; import static org.geysermc.floodgate.util.ReflectionUtils.getField; +import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName; import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass; +import static org.geysermc.floodgate.util.ReflectionUtils.invoke; import static org.geysermc.floodgate.util.ReflectionUtils.setValue; import io.netty.channel.Channel; import io.netty.util.AttributeKey; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.net.InetSocketAddress; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -48,6 +51,11 @@ public final class VelocityProxyDataHandler extends CommonDataHandler { private static final Field HANDSHAKE_SERVER_ADDRESS; private static final Field REMOTE_ADDRESS; + private static final Class SERVER_LOGIN_PACKET; + private static final Method GET_SESSION_HANDLER; + private static final Class INITIAL_LOGIN_SESSION_HANDLER; + private static final Field FORCE_KEY_AUTHENTICATION; + static { Class iic = getPrefixedClass("connection.client.InitialInboundConnection"); checkNotNull(iic, "InitialInboundConnection class cannot be null"); @@ -63,6 +71,20 @@ public final class VelocityProxyDataHandler extends CommonDataHandler { Class minecraftConnection = getPrefixedClass("connection.MinecraftConnection"); REMOTE_ADDRESS = getField(minecraftConnection, "remoteAddress"); + checkNotNull(REMOTE_ADDRESS, "remoteAddress cannot be null"); + + SERVER_LOGIN_PACKET = getPrefixedClass("protocol.packet.ServerLogin"); + checkNotNull(SERVER_LOGIN_PACKET, "ServerLogin packet class cannot be null"); + + GET_SESSION_HANDLER = getMethodByName(minecraftConnection, "getSessionHandler", true); + checkNotNull(GET_SESSION_HANDLER, "getSessionHandler method cannot be null"); + + INITIAL_LOGIN_SESSION_HANDLER = + getPrefixedClass("connection.client.InitialLoginSessionHandler"); + checkNotNull(INITIAL_LOGIN_SESSION_HANDLER, "InitialLoginSessionHandler cannot be null"); + + // allowed to be null if it's an old Velocity version + FORCE_KEY_AUTHENTICATION = getField(INITIAL_LOGIN_SESSION_HANDLER, "forceKeyAuthentication"); } private final FloodgateLogger logger; @@ -94,19 +116,35 @@ protected boolean shouldRemoveHandler(HandshakeResult result) { FloodgatePlayer player = result.getFloodgatePlayer(); logger.info("Floodgate player who is logged in as {} {} joined", player.getCorrectUsername(), player.getCorrectUniqueId()); + + // the way Velocity stores whether to force key authentication + boolean forceKeyAuthentication = Boolean.getBoolean("auth.forceSecureProfiles"); + // we need the login packet to bypass the 'force key authentication' + return !forceKeyAuthentication; } return super.shouldRemoveHandler(result); } @Override public boolean channelRead(Object packet) { - // we're only interested in the Handshake packet. - // it should be the first packet but you never know if (HANDSHAKE_PACKET.isInstance(packet)) { handle(packet, getCastedValue(packet, HANDSHAKE_SERVER_ADDRESS)); // otherwise, it'll get read twice. once by the packet queue and once by this method return false; } + + // at this point we know that forceKeyAuthentication is enabled + if (SERVER_LOGIN_PACKET.isInstance(packet)) { + Object minecraftConnection = ctx.pipeline().get("handler"); + Object sessionHandler = invoke(minecraftConnection, GET_SESSION_HANDLER); + if (!INITIAL_LOGIN_SESSION_HANDLER.isInstance(sessionHandler)) { + logger.error("Expected player's session handler to be InitialLoginSessionHandler"); + return true; + } + if (FORCE_KEY_AUTHENTICATION != null) { + setValue(sessionHandler, FORCE_KEY_AUTHENTICATION, false); + } + } return true; } } From a7a6366ec1038a4ccdf1f836471a4c7002109f06 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 11 Jun 2022 15:39:12 +0200 Subject: [PATCH 023/113] Patch for people who updated to 2.2 early, and fixed previous push. The config updater didn't re-add the quotes that strings with special characters (or no characters) should have, which resulted in the usernamePrefix becoming invalid or null. While this has been fixed for people that use the config updater with the latest version, people that already updated can't update again, and would have to edit the config manually. --- .../pluginmessage/BungeeSkinApplier.java | 19 ++++++++++++++----- .../floodgate/config/FloodgateConfig.java | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index ee10c47a..5c0dce97 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -26,6 +26,7 @@ package org.geysermc.floodgate.pluginmessage; import static com.google.common.base.Preconditions.checkNotNull; +import static org.geysermc.floodgate.util.ReflectionUtils.getConstructor; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName; @@ -46,6 +47,7 @@ @RequiredArgsConstructor public final class BungeeSkinApplier implements SkinApplier { + private static final Constructor LOGIN_RESULT_CONSTRUCTOR; private static final Field LOGIN_RESULT_FIELD; private static final Method SET_PROPERTIES_METHOD; @@ -53,15 +55,20 @@ public final class BungeeSkinApplier implements SkinApplier { private static final Constructor PROPERTY_CONSTRUCTOR; static { + PROPERTY_CLASS = ReflectionUtils.getClassOrFallbackPrefixed( + "protocol.Property", "connection.LoginResult$Property" + ); + + LOGIN_RESULT_CONSTRUCTOR = getConstructor( + LoginResult.class, true, + String.class, String.class, Array.newInstance(PROPERTY_CLASS, 0).getClass() + ); + LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class); checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null"); SET_PROPERTIES_METHOD = getMethodByName(LoginResult.class, "setProperties", true); - PROPERTY_CLASS = ReflectionUtils.getClassOrFallbackPrefixed( - "protocol.Property", "connection.LoginResult.Property" - ); - PROPERTY_CONSTRUCTOR = ReflectionUtils.getConstructor( PROPERTY_CLASS, true, String.class, String.class, String.class @@ -91,7 +98,9 @@ public void applySkin(FloodgatePlayer uuid, SkinData skinData) { // which Floodgate players don't have if (loginResult == null) { // id and name are unused and properties will be overridden - loginResult = new LoginResult(null, null, null); + loginResult = (LoginResult) ReflectionUtils.newInstance( + LOGIN_RESULT_CONSTRUCTOR, null, null, null + ); ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult); } diff --git a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java index 167c40f6..b7b6b866 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java +++ b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java @@ -40,7 +40,7 @@ @Getter public class FloodgateConfig implements GenericPostInitializeCallback { private String keyFileName; - private String usernamePrefix; + private String usernamePrefix = ""; private boolean replaceSpaces; private String defaultLocale; From a46f43d19aeaf5870f9331d7dbc0f204fff243cc Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 13 Jun 2022 15:29:45 -0400 Subject: [PATCH 024/113] Fix Velocity modern forwarding with 1.19 Fixes https://github.com/GeyserMC/Geyser/issues/3039, #321 --- .../floodgate/util/ReflectionUtils.java | 29 +++++++++++ .../geysermc/floodgate/util/ClassNames.java | 50 ++++++++++++++++--- .../geysermc/floodgate/util/ProxyUtils.java | 5 +- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java index 13d16d8a..80352d87 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java @@ -255,6 +255,25 @@ public static Object getValue(Object instance, Field field) { } } + /** + * Get the value of a boolean field. This method first makes the field accessible and then gets + * the value.
This method will return false instead of throwing an exception, but it'll log + * the stacktrace to the console. + * + * @param instance the instance to get the value from + * @param field the field to get the value from + * @return the value when succeeded, otherwise null + */ + public static boolean getBooleanValue(Object instance, Field field) { + makeAccessible(field); + try { + return field.getBoolean(instance); + } catch (IllegalArgumentException | IllegalAccessException exception) { + exception.printStackTrace(); + return false; + } + } + /** * Get the value of the given field by finding the field and then get the value of it. * @@ -300,6 +319,16 @@ public static T castedStaticValue(Field field) { return getCastedValue(null, field); } + public static boolean castedStaticBooleanValue(Field field) { + makeAccessible(field); + try { + return field.getBoolean(null); + } catch (IllegalArgumentException | IllegalAccessException exception) { + exception.printStackTrace(); + return false; + } + } + /** * Set the value of a field. This method make the field accessible and then sets the value.
* This method doesn't throw an exception when failed, but it'll log the error to the console. diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 4d0908e7..22c7d688 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -25,10 +25,15 @@ package org.geysermc.floodgate.util; +import static org.geysermc.floodgate.util.ReflectionUtils.castedStaticBooleanValue; +import static org.geysermc.floodgate.util.ReflectionUtils.getBooleanValue; import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallback; +import static org.geysermc.floodgate.util.ReflectionUtils.getClassSilently; import static org.geysermc.floodgate.util.ReflectionUtils.getField; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; import static org.geysermc.floodgate.util.ReflectionUtils.getMethod; +import static org.geysermc.floodgate.util.ReflectionUtils.getValue; +import static org.geysermc.floodgate.util.ReflectionUtils.invoke; import com.google.common.base.Preconditions; import com.mojang.authlib.GameProfile; @@ -37,6 +42,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.SocketAddress; +import java.util.function.BooleanSupplier; +import javax.annotation.CheckForNull; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.checkerframework.checker.nullness.qual.Nullable; @@ -61,7 +68,7 @@ public class ClassNames { public static final Field PACKET_LISTENER; @Nullable public static final Field PAPER_DISABLE_USERNAME_VALIDATION; - @Nullable public static final Field PAPER_VELOCITY_SUPPORT; + @Nullable public static final BooleanSupplier PAPER_VELOCITY_SUPPORT; public static final Method GET_PROFILE_METHOD; public static final Method LOGIN_DISCONNECT; @@ -182,14 +189,41 @@ public class ClassNames { BUNGEE = getField(spigotConfig, "bungee"); checkNotNull(BUNGEE, "Bungee field"); - Class paperConfig = ReflectionUtils.getClassSilently( - "com.destroystokyo.paper.PaperConfig"); - - PAPER_VELOCITY_SUPPORT = - paperConfig == null ? null : getField(paperConfig, "velocitySupport"); + Class paperConfigNew = getClassSilently( + "io.papermc.paper.configuration.GlobalConfiguration"); + if (paperConfigNew != null) { + // 1.19 and later + Method paperConfigGet = checkNotNull(getMethod(paperConfigNew, "get"), + "GlobalConfiguration get"); + Field paperConfigProxies = checkNotNull(getField(paperConfigNew, "proxies"), + "Proxies field"); + Field paperConfigVelocity = checkNotNull( + getField(paperConfigProxies.getType(), "velocity"), + "velocity field"); + Field paperVelocityEnabled = checkNotNull( + getField(paperConfigVelocity.getType(), "enabled"), + "Velocity enabled field"); + PAPER_VELOCITY_SUPPORT = () -> { + Object paperConfigInstance = invoke(null, paperConfigGet); + Object proxiesInstance = getValue(paperConfigInstance, paperConfigProxies); + Object velocityInstance = getValue(proxiesInstance, paperConfigVelocity); + return getBooleanValue(velocityInstance, paperVelocityEnabled); + }; + } else { + // Pre-1.19 + Class paperConfig = getClassSilently( + "com.destroystokyo.paper.PaperConfig"); + + if (paperConfig != null) { + Field velocitySupport = getField(paperConfig, "velocitySupport"); + PAPER_VELOCITY_SUPPORT = () -> castedStaticBooleanValue(velocitySupport); + } else { + PAPER_VELOCITY_SUPPORT = null; + } + } } - private static void checkNotNull(Object toCheck, String objectName) { - Preconditions.checkNotNull(toCheck, objectName + " cannot be null"); + private static T checkNotNull(@CheckForNull T toCheck, @CheckForNull String objectName) { + return Preconditions.checkNotNull(toCheck, objectName + " cannot be null"); } } diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java index 9d982850..d9d7791d 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ProxyUtils.java @@ -25,7 +25,6 @@ package org.geysermc.floodgate.util; -@SuppressWarnings("ConstantConditions") public final class ProxyUtils { public static boolean isProxyData() { @@ -33,7 +32,7 @@ public static boolean isProxyData() { } private static boolean isBungeeData() { - return ReflectionUtils.castedStaticValue(ClassNames.BUNGEE); + return ReflectionUtils.castedStaticBooleanValue(ClassNames.BUNGEE); } private static boolean isVelocitySupport() { @@ -41,6 +40,6 @@ private static boolean isVelocitySupport() { return false; } - return ReflectionUtils.castedStaticValue(ClassNames.PAPER_VELOCITY_SUPPORT); + return ClassNames.PAPER_VELOCITY_SUPPORT.getAsBoolean(); } } \ No newline at end of file From 6e2c19f1186e177857c99f7ee9153695f7828c9e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 16 Jun 2022 20:09:45 -0400 Subject: [PATCH 025/113] Velocity modern forwarding support doesn't exist pre-1.13 --- .../src/main/java/org/geysermc/floodgate/util/ClassNames.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 22c7d688..1ca5105a 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -216,7 +216,9 @@ public class ClassNames { if (paperConfig != null) { Field velocitySupport = getField(paperConfig, "velocitySupport"); - PAPER_VELOCITY_SUPPORT = () -> castedStaticBooleanValue(velocitySupport); + // velocitySupport field is null pre-1.13 + PAPER_VELOCITY_SUPPORT = velocitySupport != null ? + () -> castedStaticBooleanValue(velocitySupport) : null; } else { PAPER_VELOCITY_SUPPORT = null; } From 69aacfa91b8172aae80a04b138627c87fa9849c3 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 19 Jun 2022 23:00:18 +0200 Subject: [PATCH 026/113] Started using plugin messages internally. Started subcommand refactor --- build-logic/src/main/kotlin/Versions.kt | 1 + core/build.gradle.kts | 1 + .../geysermc/floodgate/FloodgatePlatform.java | 7 +-- .../floodgate/api/ProxyFloodgateApi.java | 16 ++---- .../floodgate/api/SimpleFloodgateApi.java | 16 +++--- .../floodgate/command/WhitelistCommand.java | 5 +- .../command/main/FirewallCheckSubcommand.java | 40 +++++++++++---- .../floodgate/command/main/MainCommand.java | 41 ++++++++------- .../floodgate/event/ShutdownEvent.java | 29 +++++++++++ .../event/util/ListenerAnnotationMatcher.java | 38 ++++++++++++++ .../floodgate/link/CommonPlayerLink.java | 9 ++++ .../floodgate/link/GlobalPlayerLinking.java | 12 +++-- .../floodgate/module/CommonModule.java | 44 ++++++++++++---- .../floodgate/module/ProxyCommonModule.java | 16 +----- .../floodgate/module/ServerCommonModule.java | 17 ++----- .../geysermc/floodgate/news/NewsChecker.java | 51 ++++++++++++------- .../platform/command/FloodgateSubCommand.java | 40 +++++++++++++++ .../util/{HttpUtils.java => HttpClient.java} | 43 +++++++++------- .../geysermc/floodgate/VelocityPlugin.java | 6 +++ 19 files changed, 298 insertions(+), 134 deletions(-) create mode 100644 core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java create mode 100644 core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java create mode 100644 core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java rename core/src/main/java/org/geysermc/floodgate/util/{HttpUtils.java => HttpClient.java} (81%) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 740288d8..316ddc0f 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -34,6 +34,7 @@ object Versions { const val snakeyamlVersion = "1.28" const val cloudVersion = "1.5.0" const val bstatsVersion = "3.0.0" + const val mbassadorVersion = "1.3.2" const val javaWebsocketVersion = "1.5.2" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 02fec9dd..258d98c5 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { api("cloud.commandframework", "cloud-core", Versions.cloudVersion) api("org.yaml", "snakeyaml", Versions.snakeyamlVersion) api("org.bstats", "bstats-base", Versions.bstatsVersion) + api("net.engio", "mbassador", Versions.mbassadorVersion) } // present on all platforms diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index 7b963d73..c02fcfc8 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -33,6 +33,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.UUID; +import net.engio.mbassy.bus.common.PubSubSupport; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.InstanceHolder; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; @@ -43,6 +44,7 @@ import org.geysermc.floodgate.config.ConfigLoader; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfigHolder; +import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.module.ConfigLoadedModule; import org.geysermc.floodgate.module.PostInitializeModule; @@ -130,6 +132,8 @@ public boolean enable(Module... postInitializeModules) { } public boolean disable() { + guice.getInstance(PubSubSupport.class).publish(new ShutdownEvent()); + if (injector != null && injector.canRemoveInjection()) { try { if (!injector.removeInjection()) { @@ -139,9 +143,6 @@ public boolean disable() { logger.error("Failed to remove the injection!", exception); } } - - guice.getInstance(NewsChecker.class).shutdown(); - api.getPlayerLink().stop(); return true; } diff --git a/core/src/main/java/org/geysermc/floodgate/api/ProxyFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/ProxyFloodgateApi.java index a3336e09..ede56730 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/ProxyFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/ProxyFloodgateApi.java @@ -25,24 +25,14 @@ package org.geysermc.floodgate.api; +import com.google.inject.Inject; import java.nio.charset.StandardCharsets; -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.config.FloodgateConfigHolder; import org.geysermc.floodgate.crypto.FloodgateCipher; -import org.geysermc.floodgate.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.util.BedrockData; public final class ProxyFloodgateApi extends SimpleFloodgateApi { - private final FloodgateCipher cipher; - - public ProxyFloodgateApi( - PluginMessageManager pluginMessageManager, - FloodgateConfigHolder configHolder, - FloodgateLogger logger, - FloodgateCipher cipher) { - super(pluginMessageManager, configHolder, logger); - this.cipher = cipher; - } + @Inject + private FloodgateCipher cipher; public byte[] createEncryptedData(BedrockData bedrockData) { try { diff --git a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java index 94db6743..4fd89f33 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java @@ -30,13 +30,13 @@ import com.google.common.collect.ImmutableSet; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.inject.Inject; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import lombok.RequiredArgsConstructor; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.api.logger.FloodgateLogger; @@ -47,10 +47,9 @@ import org.geysermc.floodgate.pluginmessage.channel.FormChannel; import org.geysermc.floodgate.pluginmessage.channel.TransferChannel; import org.geysermc.floodgate.util.Constants; -import org.geysermc.floodgate.util.HttpUtils; +import org.geysermc.floodgate.util.HttpClient; import org.geysermc.floodgate.util.Utils; -@RequiredArgsConstructor public class SimpleFloodgateApi implements FloodgateApi { private final Map players = new HashMap<>(); private final Cache pendingRemove = @@ -58,9 +57,10 @@ public class SimpleFloodgateApi implements FloodgateApi { .expireAfterWrite(20, TimeUnit.SECONDS) .build(); - private final PluginMessageManager pluginMessageManager; - private final FloodgateConfigHolder configHolder; - private final FloodgateLogger logger; + @Inject private PluginMessageManager pluginMessageManager; + @Inject private FloodgateConfigHolder configHolder; + @Inject private HttpClient httpClient; + @Inject private FloodgateLogger logger; @Override public String getPlayerPrefix() { @@ -148,7 +148,7 @@ public CompletableFuture getXuidFor(String gamertag) { return Utils.failedFuture(new IllegalStateException("Received an invalid gamertag")); } - return HttpUtils.asyncGet(Constants.GET_XUID_URL + gamertag) + return httpClient.asyncGet(Constants.GET_XUID_URL + gamertag) .thenApply(result -> { JsonObject response = result.getResponse(); @@ -163,7 +163,7 @@ public CompletableFuture getXuidFor(String gamertag) { @Override public CompletableFuture getGamertagFor(long xuid) { - return HttpUtils.asyncGet(Constants.GET_GAMERTAG_URL + xuid) + return httpClient.asyncGet(Constants.GET_GAMERTAG_URL + xuid) .thenApply(result -> { JsonObject response = result.getResponse(); diff --git a/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java b/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java index 45287f9e..b87a20ee 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java @@ -49,10 +49,11 @@ import org.geysermc.floodgate.player.audience.ProfileAudience; import org.geysermc.floodgate.player.audience.ProfileAudienceArgument; import org.geysermc.floodgate.util.Constants; -import org.geysermc.floodgate.util.HttpUtils; +import org.geysermc.floodgate.util.HttpClient; public class WhitelistCommand implements FloodgateCommand { @Inject private FloodgateConfig config; + @Inject private HttpClient httpClient; @Inject private FloodgateLogger logger; @Override @@ -128,7 +129,7 @@ public void performCommand(CommandContext context, boolean add) { final String strippedName = name; // We need to get the UUID of the player if it's not manually specified - HttpUtils.asyncGet(Constants.GET_XUID_URL + name) + httpClient.asyncGet(Constants.GET_XUID_URL + name) .whenComplete((result, error) -> { if (error != null) { sender.sendMessage(Message.API_UNAVAILABLE); diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java index 66f439b7..6fa989f5 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java @@ -29,20 +29,40 @@ import cloud.commandframework.context.CommandContext; import com.google.gson.JsonElement; +import com.google.inject.Inject; import it.unimi.dsi.fastutil.Pair; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BooleanSupplier; +import org.geysermc.floodgate.command.util.Permission; +import org.geysermc.floodgate.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.util.Constants; -import org.geysermc.floodgate.util.HttpUtils; -import org.geysermc.floodgate.util.HttpUtils.HttpResponse; +import org.geysermc.floodgate.util.HttpClient; +import org.geysermc.floodgate.util.HttpClient.HttpResponse; import org.geysermc.floodgate.util.Utils; -final class FirewallCheckSubcommand { - private FirewallCheckSubcommand() {} +final class FirewallCheckSubcommand extends FloodgateSubCommand { + @Inject + private HttpClient httpClient; - static void executeFirewall(CommandContext context) { + @Override + public String name() { + return "firewall"; + } + + @Override + public String description() { + return "Check if your outgoing firewall allows Floodgate to work properly"; + } + + @Override + public Permission permission() { + return Permission.COMMAND_MAIN_FIREWALL; + } + + @Override + public void execute(CommandContext context) { UserAudience sender = context.getSender(); executeChecks( globalApiCheck(sender) @@ -54,12 +74,12 @@ static void executeFirewall(CommandContext context) { ); } - private static BooleanSupplier globalApiCheck(UserAudience sender) { + private BooleanSupplier globalApiCheck(UserAudience sender) { return executeFirewallText( sender, "global api", () -> { HttpResponse response = - HttpUtils.get(Constants.HEALTH_URL, JsonElement.class); + httpClient.get(Constants.HEALTH_URL, JsonElement.class); if (!response.isCodeOk()) { throw new IllegalStateException(String.format( @@ -70,7 +90,7 @@ private static BooleanSupplier globalApiCheck(UserAudience sender) { }); } - private static BooleanSupplier executeFirewallText( + private BooleanSupplier executeFirewallText( UserAudience sender, String name, Runnable runnable) { return () -> { sender.sendMessage(COLOR_CHAR + "eTesting " + name + "..."); @@ -86,9 +106,7 @@ private static BooleanSupplier executeFirewallText( }; } - private static CompletableFuture> executeChecks( - BooleanSupplier... checks) { - + private CompletableFuture> executeChecks(BooleanSupplier... checks) { return CompletableFuture.supplyAsync(() -> { AtomicInteger okCount = new AtomicInteger(); AtomicInteger failCount = new AtomicInteger(); diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java index 093289fe..f5b45e53 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java @@ -32,14 +32,25 @@ import cloud.commandframework.Command.Builder; import cloud.commandframework.CommandManager; import cloud.commandframework.context.CommandContext; +import com.google.inject.Inject; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; -import java.util.function.Consumer; -import lombok.RequiredArgsConstructor; import org.geysermc.floodgate.command.util.Permission; import org.geysermc.floodgate.platform.command.FloodgateCommand; +import org.geysermc.floodgate.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.player.UserAudience; public final class MainCommand implements FloodgateCommand { + private final List subCommands = new ArrayList<>(); + + @Inject + public void createSubCommands(FirewallCheckSubcommand firewallCheckSubcommand) { + //todo move subcommand logic to a separate class + subCommands.clear(); + subCommands.add(firewallCheckSubcommand); + } + @Override public Command buildCommand(CommandManager commandManager) { Builder builder = commandManager.commandBuilder( @@ -49,11 +60,11 @@ public Command buildCommand(CommandManager commandMa .permission(Permission.COMMAND_MAIN.get()) .handler(this::execute); - for (SubCommand subCommand : SubCommand.VALUES) { + for (FloodgateSubCommand subCommand : subCommands) { commandManager.command(builder - .literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description) - .permission(subCommand.permission.get()) - .handler(subCommand.executor::accept) + .literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description()) + .permission(subCommand.permission().get()) + .handler(subCommand::execute) ); } @@ -65,27 +76,15 @@ public Command buildCommand(CommandManager commandMa public void execute(CommandContext context) { StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n"); - for (SubCommand subCommand : SubCommand.VALUES) { - if (context.getSender().hasPermission(subCommand.permission.get())) { + for (FloodgateSubCommand subCommand : subCommands) { + if (context.getSender().hasPermission(subCommand.permission().get())) { helpMessage.append('\n').append(COLOR_CHAR).append('b') .append(subCommand.name().toLowerCase(Locale.ROOT)) .append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7') - .append(subCommand.description); + .append(subCommand.description()); } } context.getSender().sendMessage(helpMessage.toString()); } - - @RequiredArgsConstructor - enum SubCommand { - FIREWALL("Check if your outgoing firewall allows Floodgate to work properly", - Permission.COMMAND_MAIN_FIREWALL, FirewallCheckSubcommand::executeFirewall); - - static final SubCommand[] VALUES = values(); - - final String description; - final Permission permission; - final Consumer> executor; - } } diff --git a/core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java b/core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java new file mode 100644 index 00000000..345c9f30 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.event; + +public class ShutdownEvent { +} diff --git a/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java b/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java new file mode 100644 index 00000000..614a6a52 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.event.util; + +import com.google.inject.TypeLiteral; +import com.google.inject.matcher.AbstractMatcher; +import net.engio.mbassy.listener.Listener; + +public class ListenerAnnotationMatcher extends AbstractMatcher> { + @Override + public boolean matches(TypeLiteral typeLiteral) { + Class rawType = typeLiteral.getRawType(); + return rawType.isAnnotationPresent(Listener.class); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java index 0973b8d9..29c9a4ea 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java +++ b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java @@ -34,6 +34,8 @@ import java.util.concurrent.Executors; import lombok.AccessLevel; import lombok.Getter; +import net.engio.mbassy.listener.Handler; +import net.engio.mbassy.listener.Listener; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.link.LinkRequest; import org.geysermc.floodgate.api.link.PlayerLink; @@ -41,8 +43,10 @@ import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.database.config.DatabaseConfig; import org.geysermc.floodgate.database.config.DatabaseConfigLoader; +import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.util.InjectorHolder; +@Listener public abstract class CommonPlayerLink implements PlayerLink { @Getter(AccessLevel.PROTECTED) private final ExecutorService executorService = Executors.newFixedThreadPool(11); @@ -102,4 +106,9 @@ public String getName() { public void stop() { executorService.shutdown(); } + + @Handler + public void onShutdown(ShutdownEvent ignored) { + stop(); + } } diff --git a/core/src/main/java/org/geysermc/floodgate/link/GlobalPlayerLinking.java b/core/src/main/java/org/geysermc/floodgate/link/GlobalPlayerLinking.java index 1ef1227e..bc57c61b 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/GlobalPlayerLinking.java +++ b/core/src/main/java/org/geysermc/floodgate/link/GlobalPlayerLinking.java @@ -29,19 +29,23 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.inject.Inject; import java.util.UUID; import java.util.concurrent.CompletableFuture; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.api.link.LinkRequestResult; import org.geysermc.floodgate.api.link.PlayerLink; -import org.geysermc.floodgate.util.HttpUtils; -import org.geysermc.floodgate.util.HttpUtils.DefaultHttpResponse; +import org.geysermc.floodgate.util.HttpClient; +import org.geysermc.floodgate.util.HttpClient.DefaultHttpResponse; import org.geysermc.floodgate.util.LinkedPlayer; import org.geysermc.floodgate.util.Utils; @Getter public class GlobalPlayerLinking extends CommonPlayerLink { + @Inject + private HttpClient httpClient; + private PlayerLink databaseImpl; public void setDatabaseImpl(PlayerLink databaseImpl) { @@ -94,7 +98,7 @@ private CompletableFuture getLinkedPlayer0(@NonNull UUID bedrockId return CompletableFuture.supplyAsync( () -> { DefaultHttpResponse response = - HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); + httpClient.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); // either the global api is down or it failed to return link if (!response.isCodeOk()) { @@ -144,7 +148,7 @@ private CompletableFuture isLinkedPlayer0(@NonNull UUID bedrockId) { return CompletableFuture.supplyAsync( () -> { DefaultHttpResponse response = - HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); + httpClient.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); if (!response.isCodeOk()) { getLogger().error( diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index f075bc22..3275b059 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -28,10 +28,17 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; +import com.google.inject.TypeLiteral; import com.google.inject.name.Named; +import com.google.inject.spi.InjectionListener; +import com.google.inject.spi.TypeEncounter; +import com.google.inject.spi.TypeListener; import io.netty.util.AttributeKey; import java.nio.file.Path; import lombok.RequiredArgsConstructor; +import net.engio.mbassy.bus.MBassador; +import net.engio.mbassy.bus.common.PubSubSupport; +import net.engio.mbassy.bus.error.IPublicationErrorHandler.ConsoleLogger; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi; @@ -48,29 +55,46 @@ import org.geysermc.floodgate.crypto.Base64Topping; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; +import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher; import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.news.NewsChecker; import org.geysermc.floodgate.packet.PacketHandlersImpl; -import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.util.Constants; +import org.geysermc.floodgate.util.HttpClient; import org.geysermc.floodgate.util.LanguageManager; @RequiredArgsConstructor public class CommonModule extends AbstractModule { + private final PubSubSupport eventBus = new MBassador<>(new ConsoleLogger(true)); private final Path dataDirectory; @Override protected void configure() { + bind(PubSubSupport.class).toInstance(eventBus); + // register every class that has the Listener annotation + bindListener(new ListenerAnnotationMatcher(), new TypeListener() { + @Override + public void hear(TypeLiteral type, TypeEncounter encounter) { + encounter.register((InjectionListener) eventBus::subscribe); + } + }); + + bind(HttpClient.class).in(Singleton.class); + bind(FloodgateApi.class).to(SimpleFloodgateApi.class); bind(PlatformInjector.class).to(CommonPlatformInjector.class); + bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class); + bind(HandshakeHandlersImpl.class).in(Singleton.class); bind(PacketHandlers.class).to(PacketHandlersImpl.class); bind(PacketHandlersImpl.class).asEagerSingleton(); + + bind(NewsChecker.class).in(Singleton.class); } @Provides @@ -116,12 +140,6 @@ public LanguageManager languageLoader( return new LanguageManager(configHolder, logger); } - @Provides - @Singleton - public HandshakeHandlersImpl handshakeHandlers() { - return new HandshakeHandlersImpl(); - } - @Provides @Singleton public FloodgateHandshakeHandler handshakeHandler( @@ -154,8 +172,16 @@ public SkinUploadManager skinUploadManager( @Provides @Singleton - public NewsChecker newsChecker(CommandUtil commandUtil, FloodgateLogger logger) { - return new NewsChecker(commandUtil, logger, Constants.GIT_BRANCH, Constants.BUILD_NUMBER); + @Named("gitBranch") + public String gitBranch() { + return Constants.GIT_BRANCH; + } + + @Provides + @Singleton + @Named("buildNumber") + public int buildNumber() { + return Constants.BUILD_NUMBER; } @Provides diff --git a/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java index bae8cf22..c479852e 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java @@ -31,12 +31,8 @@ import java.nio.file.Path; import org.geysermc.floodgate.api.ProxyFloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi; -import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.config.FloodgateConfigHolder; import org.geysermc.floodgate.config.ProxyFloodgateConfig; -import org.geysermc.floodgate.crypto.FloodgateCipher; -import org.geysermc.floodgate.pluginmessage.PluginMessageManager; public final class ProxyCommonModule extends CommonModule { public ProxyCommonModule(Path dataDirectory) { @@ -46,7 +42,9 @@ public ProxyCommonModule(Path dataDirectory) { @Override protected void configure() { super.configure(); + bind(SimpleFloodgateApi.class).to(ProxyFloodgateApi.class); + bind(ProxyFloodgateApi.class).in(Singleton.class); } @Provides @@ -55,14 +53,4 @@ protected void configure() { public Class floodgateConfigClass() { return ProxyFloodgateConfig.class; } - - @Provides - @Singleton - public ProxyFloodgateApi proxyFloodgateApi( - PluginMessageManager pluginMessageManager, - FloodgateConfigHolder configHolder, - FloodgateLogger logger, - FloodgateCipher cipher) { - return new ProxyFloodgateApi(pluginMessageManager, configHolder, logger, cipher); - } } diff --git a/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java index b1b4ab5a..4e544d18 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java @@ -30,29 +30,22 @@ import com.google.inject.name.Named; import java.nio.file.Path; import org.geysermc.floodgate.api.SimpleFloodgateApi; -import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.config.FloodgateConfigHolder; -import org.geysermc.floodgate.pluginmessage.PluginMessageManager; public final class ServerCommonModule extends CommonModule { public ServerCommonModule(Path dataDirectory) { super(dataDirectory); } + @Override + protected void configure() { + bind(SimpleFloodgateApi.class).in(Singleton.class); + } + @Provides @Singleton @Named("configClass") public Class floodgateConfigClass() { return FloodgateConfig.class; } - - @Provides - @Singleton - public SimpleFloodgateApi floodgateApi( - PluginMessageManager pluginMessageManager, - FloodgateConfigHolder configHolder, - FloodgateLogger logger) { - return new SimpleFloodgateApi(pluginMessageManager, configHolder, logger); - } } diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index 901321c3..62be4469 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -27,6 +27,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import com.google.inject.Inject; +import com.google.inject.name.Named; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -35,33 +37,39 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import net.engio.mbassy.listener.Handler; +import net.engio.mbassy.listener.Listener; import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.command.util.Permission; +import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.news.data.AnnouncementData; import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.CheckAfterData; import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.util.Constants; -import org.geysermc.floodgate.util.HttpUtils; -import org.geysermc.floodgate.util.HttpUtils.HttpResponse; -import org.geysermc.floodgate.command.util.Permission; +import org.geysermc.floodgate.util.HttpClient; +import org.geysermc.floodgate.util.HttpClient.HttpResponse; +@Listener public class NewsChecker { private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); - private final CommandUtil commandUtil; - private final FloodgateLogger logger; - private final Map activeNewsItems = new HashMap<>(); - private final String branch; - private final int build; - private boolean firstCheck; + @Inject + private CommandUtil commandUtil; + @Inject + private HttpClient httpClient; + @Inject + private FloodgateLogger logger; - public NewsChecker(CommandUtil commandUtil, FloodgateLogger logger, String branch, int build) { - this.commandUtil = commandUtil; - this.logger = logger; - this.branch = branch; - this.build = build; - } + @Inject + @Named("gitBranch") + private String branch; + @Inject + @Named("buildNumber") + private int build; + + private boolean firstCheck; public void start() { executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES); @@ -72,10 +80,10 @@ private void schedule(long delayMs) { } private void checkNews() { - HttpResponse response = - HttpUtils.getSilent( - Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME, - JsonArray.class); + HttpResponse response = httpClient.getSilent( + Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME, + JsonArray.class + ); JsonArray array = response.getResponse(); @@ -197,4 +205,9 @@ private void activateNews(NewsItem item) { public void shutdown() { executorService.shutdown(); } + + @Handler + public void onShutdown(ShutdownEvent ignored) { + shutdown(); + } } diff --git a/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java b/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java new file mode 100644 index 00000000..25515ddc --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.platform.command; + +import cloud.commandframework.context.CommandContext; +import org.geysermc.floodgate.command.util.Permission; +import org.geysermc.floodgate.player.UserAudience; + +public abstract class FloodgateSubCommand { + public abstract String name(); + + public abstract String description(); + + public abstract Permission permission(); + + public abstract void execute(CommandContext context); +} diff --git a/core/src/main/java/org/geysermc/floodgate/util/HttpUtils.java b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java similarity index 81% rename from core/src/main/java/org/geysermc/floodgate/util/HttpUtils.java rename to core/src/main/java/org/geysermc/floodgate/util/HttpClient.java index 56ef2540..c03fd49e 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/HttpUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java @@ -37,34 +37,38 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; +import net.engio.mbassy.listener.Handler; +import net.engio.mbassy.listener.Listener; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.floodgate.event.ShutdownEvent; // resources are properly closed and ignoring the original stack trace is intended @SuppressWarnings({"PMD.CloseResource", "PMD.PreserveStackTrace"}) -public class HttpUtils { - private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); - - private static final Gson GSON = new Gson(); +@Listener +public class HttpClient { private static final String USER_AGENT = "GeyserMC/Floodgate"; - public static CompletableFuture asyncGet(String urlString) { - return CompletableFuture.supplyAsync(() -> get(urlString), EXECUTOR_SERVICE); + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final Gson gson = new Gson(); + + public CompletableFuture asyncGet(String urlString) { + return CompletableFuture.supplyAsync(() -> get(urlString), executorService); } - public static DefaultHttpResponse get(String urlString) { + public DefaultHttpResponse get(String urlString) { return readDefaultResponse(request(urlString)); } - public static HttpResponse get(String urlString, Class clazz) { + public HttpResponse get(String urlString, Class clazz) { return readResponse(request(urlString), clazz); } - public static HttpResponse getSilent(String urlString, Class clazz) { + public HttpResponse getSilent(String urlString, Class clazz) { return readResponseSilent(request(urlString), clazz); } - private static HttpURLConnection request(String urlString) { + private HttpURLConnection request(String urlString) { HttpURLConnection connection; try { @@ -88,7 +92,7 @@ private static HttpURLConnection request(String urlString) { } @NonNull - private static HttpResponse readResponse(HttpURLConnection connection, Class clazz) { + private HttpResponse readResponse(HttpURLConnection connection, Class clazz) { InputStreamReader streamReader = createReader(connection); if (streamReader == null) { return new HttpResponse<>(-1, null); @@ -96,7 +100,7 @@ private static HttpResponse readResponse(HttpURLConnection connection, Cl try { int responseCode = connection.getResponseCode(); - T response = GSON.fromJson(streamReader, clazz); + T response = gson.fromJson(streamReader, clazz); return new HttpResponse<>(responseCode, response); } catch (Exception ignored) { return new HttpResponse<>(-1, null); @@ -109,9 +113,7 @@ private static HttpResponse readResponse(HttpURLConnection connection, Cl } @NonNull - private static HttpResponse readResponseSilent( - HttpURLConnection connection, - Class clazz) { + private HttpResponse readResponseSilent(HttpURLConnection connection, Class clazz) { try { return readResponse(connection, clazz); } catch (Exception ignored) { @@ -120,7 +122,7 @@ private static HttpResponse readResponseSilent( } @NonNull - private static DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) { + private DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) { InputStreamReader streamReader = createReader(connection); if (streamReader == null) { return new DefaultHttpResponse(-1, null); @@ -128,7 +130,7 @@ private static DefaultHttpResponse readDefaultResponse(HttpURLConnection connect try { int responseCode = connection.getResponseCode(); - JsonObject response = GSON.fromJson(streamReader, JsonObject.class); + JsonObject response = gson.fromJson(streamReader, JsonObject.class); return new DefaultHttpResponse(responseCode, response); } catch (Exception exception) { throw new RuntimeException("Failed to read response", exception); @@ -141,7 +143,7 @@ private static DefaultHttpResponse readDefaultResponse(HttpURLConnection connect } @Nullable - private static InputStreamReader createReader(HttpURLConnection connection) { + private InputStreamReader createReader(HttpURLConnection connection) { InputStream stream; try { stream = connection.getInputStream(); @@ -160,6 +162,11 @@ private static InputStreamReader createReader(HttpURLConnection connection) { return null; } + @Handler + public void onShutdown(ShutdownEvent ignored) { + executorService.shutdown(); + } + @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public static class HttpResponse { diff --git a/velocity/src/main/java/org/geysermc/floodgate/VelocityPlugin.java b/velocity/src/main/java/org/geysermc/floodgate/VelocityPlugin.java index 259d29a7..d7c16754 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/VelocityPlugin.java +++ b/velocity/src/main/java/org/geysermc/floodgate/VelocityPlugin.java @@ -29,6 +29,7 @@ import com.google.inject.Injector; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.plugin.annotation.DataDirectory; import java.nio.file.Path; import org.geysermc.floodgate.api.logger.FloodgateLogger; @@ -69,4 +70,9 @@ public void onProxyInitialization(ProxyInitializeEvent event) { new PluginMessageModule() ); } + + @Subscribe + public void onProxyShutdown(ProxyShutdownEvent event) { + platform.disable(); + } } From 1815613be60bcbb8c86f541c421700d75b570ad7 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 3 Jul 2022 22:03:52 +0200 Subject: [PATCH 027/113] Removed config holder and changed a few things --- .../floodgate/api/logger/FloodgateLogger.java | 13 +---- build-logic/src/main/kotlin/Versions.kt | 2 +- .../module/BungeePlatformModule.java | 7 +-- .../geysermc/floodgate/FloodgatePlatform.java | 57 +++---------------- .../floodgate/api/SimpleFloodgateApi.java | 6 +- .../floodgate/command/main/MainCommand.java | 19 ++----- .../floodgate/config/ConfigLoader.java | 12 +--- .../logger/JavaUtilFloodgateLogger.java | 29 ++++------ .../floodgate/module/CommonModule.java | 31 ++++------ .../floodgate/module/ProxyCommonModule.java | 6 ++ .../floodgate/module/ServerCommonModule.java | 1 + .../command/SubCommands.java} | 45 +++++++-------- .../player/FloodgateHandshakeHandler.java | 16 +++--- .../floodgate/util/LanguageManager.java | 30 +++------- .../geysermc/floodgate/SpigotPlatform.java | 10 ---- .../module/SpigotPlatformModule.java | 7 +-- .../logger/Slf4jFloodgateLogger.java | 31 +++++----- .../module/VelocityPlatformModule.java | 9 +-- 18 files changed, 99 insertions(+), 232 deletions(-) rename core/src/main/java/org/geysermc/floodgate/{config/FloodgateConfigHolder.java => platform/command/SubCommands.java} (56%) diff --git a/api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java b/api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java index d1d533a8..e3afee90 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java +++ b/api/src/main/java/org/geysermc/floodgate/api/logger/FloodgateLogger.java @@ -80,18 +80,7 @@ public interface FloodgateLogger { void trace(String message, Object... args); /** - * Enables debug mode for the Floodgate logger. - */ - void enableDebug(); - - /** - * Disables debug mode for the Floodgate logger. Debug messages can still be sent after running - * this method, but they will be hidden from the console. - */ - void disableDebug(); - - /** - * Returns if debugging is enabled + * Returns true if debugging is enabled */ boolean isDebug(); } diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 316ddc0f..9e3f4880 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -29,7 +29,7 @@ object Versions { const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" - const val guiceVersion = "5.0.1" + const val guiceVersion = "5.1.0" const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" const val cloudVersion = "1.5.0" diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java index cbe9b5e5..b8543417 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java +++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java @@ -66,6 +66,7 @@ public final class BungeePlatformModule extends AbstractModule { @Override protected void configure() { bind(PlatformUtils.class).to(BungeePlatformUtils.class); + bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); } @Provides @@ -74,12 +75,6 @@ public Plugin bungeePlugin() { return plugin; } - @Provides - @Singleton - public FloodgateLogger floodgateLogger(LanguageManager languageManager) { - return new JavaUtilFloodgateLogger(plugin.getLogger(), languageManager); - } - /* Commands / Listeners */ diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index c02fcfc8..3f511d83 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -28,10 +28,6 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; -import com.google.inject.name.Named; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.UUID; import net.engio.mbassy.bus.common.PubSubSupport; import org.geysermc.floodgate.api.FloodgateApi; @@ -41,12 +37,9 @@ import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.packet.PacketHandlers; -import org.geysermc.floodgate.config.ConfigLoader; import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.config.FloodgateConfigHolder; import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.link.PlayerLinkLoader; -import org.geysermc.floodgate.module.ConfigLoadedModule; import org.geysermc.floodgate.module.PostInitializeModule; import org.geysermc.floodgate.news.NewsChecker; import org.geysermc.floodgate.util.Metrics; @@ -54,51 +47,16 @@ public class FloodgatePlatform { private static final UUID KEY = UUID.randomUUID(); - private final FloodgateApi api; - private final PlatformInjector injector; + @Inject private FloodgateApi api; + @Inject private PlatformInjector injector; - private final FloodgateLogger logger; + @Inject private FloodgateLogger logger; - private FloodgateConfig config; - private Injector guice; + @Inject private FloodgateConfig config; + @Inject private Injector guice; @Inject - public FloodgatePlatform( - FloodgateApi api, - PlatformInjector platformInjector, - FloodgateLogger logger, - Injector guice) { - - this.api = api; - this.injector = platformInjector; - this.logger = logger; - this.guice = guice; - } - - @Inject - public void init( - @Named("dataDirectory") Path dataDirectory, - ConfigLoader configLoader, - FloodgateConfigHolder configHolder, - PacketHandlers packetHandlers, - HandshakeHandlers handshakeHandlers) { - - if (!Files.isDirectory(dataDirectory)) { - try { - Files.createDirectory(dataDirectory); - } catch (IOException exception) { - logger.error("Failed to create the data folder", exception); - throw new RuntimeException("Failed to create the data folder", exception); - } - } - - config = configLoader.load(); - if (config.isDebug()) { - logger.enableDebug(); - } - - configHolder.set(config); - guice = guice.createChildInjector(new ConfigLoadedModule(config)); + public void init(PacketHandlers packetHandlers, HandshakeHandlers handshakeHandlers) { PlayerLink link = guice.getInstance(PlayerLinkLoader.class).load(); InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY); @@ -131,7 +89,7 @@ public boolean enable(Module... postInitializeModules) { return true; } - public boolean disable() { + public void disable() { guice.getInstance(PubSubSupport.class).publish(new ShutdownEvent()); if (injector != null && injector.canRemoveInjection()) { @@ -143,7 +101,6 @@ public boolean disable() { logger.error("Failed to remove the injection!", exception); } } - return true; } public boolean isProxy() { diff --git a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java index 4fd89f33..0309eb2d 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java @@ -42,7 +42,7 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.unsafe.Unsafe; -import org.geysermc.floodgate.config.FloodgateConfigHolder; +import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.pluginmessage.channel.FormChannel; import org.geysermc.floodgate.pluginmessage.channel.TransferChannel; @@ -58,13 +58,13 @@ public class SimpleFloodgateApi implements FloodgateApi { .build(); @Inject private PluginMessageManager pluginMessageManager; - @Inject private FloodgateConfigHolder configHolder; + @Inject private FloodgateConfig config; @Inject private HttpClient httpClient; @Inject private FloodgateLogger logger; @Override public String getPlayerPrefix() { - return configHolder.get().getUsernamePrefix(); + return config.getUsernamePrefix(); } @Override diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java index f5b45e53..a2de48fa 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java @@ -32,23 +32,16 @@ import cloud.commandframework.Command.Builder; import cloud.commandframework.CommandManager; import cloud.commandframework.context.CommandContext; -import com.google.inject.Inject; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import org.geysermc.floodgate.command.util.Permission; import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.FloodgateSubCommand; +import org.geysermc.floodgate.platform.command.SubCommands; import org.geysermc.floodgate.player.UserAudience; -public final class MainCommand implements FloodgateCommand { - private final List subCommands = new ArrayList<>(); - - @Inject - public void createSubCommands(FirewallCheckSubcommand firewallCheckSubcommand) { - //todo move subcommand logic to a separate class - subCommands.clear(); - subCommands.add(firewallCheckSubcommand); +public final class MainCommand extends SubCommands implements FloodgateCommand { + public MainCommand() { + defineSubCommand(FirewallCheckSubcommand.class); } @Override @@ -60,7 +53,7 @@ public Command buildCommand(CommandManager commandMa .permission(Permission.COMMAND_MAIN.get()) .handler(this::execute); - for (FloodgateSubCommand subCommand : subCommands) { + for (FloodgateSubCommand subCommand : subCommands()) { commandManager.command(builder .literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description()) .permission(subCommand.permission().get()) @@ -76,7 +69,7 @@ public Command buildCommand(CommandManager commandMa public void execute(CommandContext context) { StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n"); - for (FloodgateSubCommand subCommand : subCommands) { + for (FloodgateSubCommand subCommand : subCommands()) { if (context.getSender().hasPermission(subCommand.permission().get())) { helpMessage.append('\n').append(COLOR_CHAR).append('b') .append(subCommand.name().toLowerCase(Locale.ROOT)) diff --git a/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java index 43cbfb3e..51272b89 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java @@ -35,7 +35,6 @@ import org.geysermc.configutils.file.codec.PathFileCodec; import org.geysermc.configutils.file.template.ResourceTemplateReader; import org.geysermc.configutils.updater.change.Changes; -import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; @@ -48,8 +47,6 @@ public final class ConfigLoader { private final KeyProducer keyProducer; private final FloodgateCipher cipher; - private final FloodgateLogger logger; - @SuppressWarnings("unchecked") public T load() { String templateFile = "config.yml"; @@ -100,21 +97,16 @@ public void generateKey(Path keyPath) { String decrypted = cipher.decryptToString(encrypted); if (!test.equals(decrypted)) { - logger.error("Whoops, we tested the generated Floodgate keys but " + - "the decrypted test message doesn't match the original.\n" + + throw new RuntimeException("Failed to decrypt test message.\n" + "Original message: " + test + "." + "Decrypted message: " + decrypted + ".\n" + "The encrypted message itself: " + new String(encrypted) ); - throw new RuntimeException( - "Tested the generated public and private key but, " + - "the decrypted message doesn't match the original!" - ); } Files.write(keyPath, key.getEncoded()); } catch (Exception exception) { - logger.error("Error while creating key", exception); + throw new RuntimeException("Error while creating key", exception); } } } diff --git a/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java b/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java index f3151ef1..5940bb3a 100644 --- a/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java +++ b/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java @@ -27,17 +27,23 @@ import static org.geysermc.floodgate.util.MessageFormatter.format; +import com.google.inject.Inject; import java.util.logging.Level; import java.util.logging.Logger; -import lombok.RequiredArgsConstructor; import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.util.LanguageManager; -@RequiredArgsConstructor public final class JavaUtilFloodgateLogger implements FloodgateLogger { - private final Logger logger; - private final LanguageManager languageManager; - private Level originLevel; + @Inject private Logger logger; + @Inject private LanguageManager languageManager; + + @Inject + private void init(FloodgateConfig config) { + if (config.isDebug()) { + logger.setLevel(Level.ALL); + } + } @Override public void error(String message, Object... args) { @@ -74,19 +80,6 @@ public void trace(String message, Object... args) { logger.finer(format(message, args)); } - @Override - public void enableDebug() { - originLevel = logger.getLevel(); - logger.setLevel(Level.ALL); - } - - @Override - public void disableDebug() { - if (originLevel != null) { - logger.setLevel(originLevel); - } - } - @Override public boolean isDebug() { return logger.getLevel() == Level.ALL; diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 3275b059..3e15eb1a 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -49,7 +49,6 @@ import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.config.ConfigLoader; import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.config.FloodgateConfigHolder; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; @@ -65,7 +64,6 @@ import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.HttpClient; -import org.geysermc.floodgate.util.LanguageManager; @RequiredArgsConstructor public class CommonModule extends AbstractModule { @@ -97,6 +95,12 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { bind(NewsChecker.class).in(Singleton.class); } + @Provides + @Singleton + public FloodgateConfig floodgateConfig(ConfigLoader configLoader) { + return configLoader.load(); + } + @Provides @Singleton public KeyProducer keyProducer() { @@ -116,28 +120,13 @@ public Path dataDirectory() { return dataDirectory; } - @Provides - @Singleton - public FloodgateConfigHolder configHolder() { - return new FloodgateConfigHolder(); - } - @Provides @Singleton public ConfigLoader configLoader( @Named("configClass") Class configClass, KeyProducer producer, - FloodgateCipher cipher, - FloodgateLogger logger) { - return new ConfigLoader(dataDirectory, configClass, producer, cipher, logger); - } - - @Provides - @Singleton - public LanguageManager languageLoader( - FloodgateConfigHolder configHolder, - FloodgateLogger logger) { - return new LanguageManager(configHolder, logger); + FloodgateCipher cipher) { + return new ConfigLoader(dataDirectory, configClass, producer, cipher); } @Provides @@ -146,12 +135,12 @@ public FloodgateHandshakeHandler handshakeHandler( HandshakeHandlersImpl handshakeHandlers, SimpleFloodgateApi api, FloodgateCipher cipher, - FloodgateConfigHolder configHolder, + FloodgateConfig config, SkinUploadManager skinUploadManager, @Named("playerAttribute") AttributeKey playerAttribute, FloodgateLogger logger) { - return new FloodgateHandshakeHandler(handshakeHandlers, api, cipher, configHolder, + return new FloodgateHandshakeHandler(handshakeHandlers, api, cipher, config, skinUploadManager, playerAttribute, logger); } diff --git a/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java index c479852e..77d52d2c 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/ProxyCommonModule.java @@ -47,6 +47,12 @@ protected void configure() { bind(ProxyFloodgateApi.class).in(Singleton.class); } + @Provides + @Singleton + public ProxyFloodgateConfig proxyFloodgateConfig(FloodgateConfig config) { + return (ProxyFloodgateConfig) config; + } + @Provides @Singleton @Named("configClass") diff --git a/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java index 4e544d18..23514824 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java @@ -39,6 +39,7 @@ public ServerCommonModule(Path dataDirectory) { @Override protected void configure() { + super.configure(); bind(SimpleFloodgateApi.class).in(Singleton.class); } diff --git a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java b/core/src/main/java/org/geysermc/floodgate/platform/command/SubCommands.java similarity index 56% rename from core/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java rename to core/src/main/java/org/geysermc/floodgate/platform/command/SubCommands.java index a4fd63b4..75ece406 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfigHolder.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/command/SubCommands.java @@ -23,37 +23,32 @@ * @link https://github.com/GeyserMC/Floodgate */ -package org.geysermc.floodgate.config; +package org.geysermc.floodgate.platform.command; -import org.geysermc.floodgate.util.FloodgateInfoHolder; +import com.google.inject.Inject; +import com.google.inject.Injector; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; -public class FloodgateConfigHolder { - private FloodgateConfig config; +public abstract class SubCommands { + private final Set> toRegister = new HashSet<>(); + private Set subCommands; - public boolean has() { - return config != null; + public void defineSubCommand(Class subCommandClass) { + toRegister.add(subCommandClass); } - public boolean isProxy() { - return config instanceof ProxyFloodgateConfig; + @Inject + public void registerSubCommands(Injector injector) { + Set subCommandSet = new HashSet<>(); + for (Class subCommand : toRegister) { + subCommandSet.add(injector.getInstance(subCommand)); + } + subCommands = Collections.unmodifiableSet(subCommandSet); } - public FloodgateConfig get() { - return config; - } - - public ProxyFloodgateConfig getAsProxy() { - return getAs(); - } - - @SuppressWarnings("unchecked") - public T getAs() { - return (T) config; - } - - public void set(FloodgateConfig config) { - this.config = config; - // for Geyser dump - FloodgateInfoHolder.setConfig(config); + protected Set subCommands() { + return subCommands; } } diff --git a/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java b/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java index 950d999c..c0a1e242 100644 --- a/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java @@ -48,7 +48,7 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.PropertyKey; -import org.geysermc.floodgate.config.FloodgateConfigHolder; +import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.util.BedrockData; @@ -60,7 +60,7 @@ public final class FloodgateHandshakeHandler { private final HandshakeHandlersImpl handshakeHandlers; private final SimpleFloodgateApi api; private final FloodgateCipher cipher; - private final FloodgateConfigHolder configHolder; + private final FloodgateConfig config; private final SkinUploadManager skinUploadManager; private final AttributeKey playerAttribute; private final FloodgateLogger logger; @@ -69,7 +69,7 @@ public FloodgateHandshakeHandler( HandshakeHandlersImpl handshakeHandlers, SimpleFloodgateApi api, FloodgateCipher cipher, - FloodgateConfigHolder configHolder, + FloodgateConfig config, SkinUploadManager skinUploadManager, AttributeKey playerAttribute, FloodgateLogger logger) { @@ -77,7 +77,7 @@ public FloodgateHandshakeHandler( this.handshakeHandlers = handshakeHandlers; this.api = api; this.cipher = cipher; - this.configHolder = configHolder; + this.config = config; this.skinUploadManager = skinUploadManager; this.playerAttribute = playerAttribute; this.logger = logger; @@ -134,7 +134,7 @@ public CompletableFuture handle( ); } catch (Exception e) { // all the other exceptions are caused by invalid/tempered Floodgate data - if (configHolder.get().isDebug()) { + if (config.isDebug()) { e.printStackTrace(); } @@ -207,10 +207,10 @@ private HandshakeResult handlePart2( try { HandshakeData handshakeData = new HandshakeDataImpl( - channel, true, bedrockData.clone(), configHolder.get(), + channel, true, bedrockData.clone(), config, linkedPlayer != null ? linkedPlayer.clone() : null, hostname); - if (configHolder.get().getPlayerLink().isRequireLink() && linkedPlayer == null) { + if (config.getPlayerLink().isRequireLink() && linkedPlayer == null) { handshakeData.setDisconnectReason("floodgate.core.not_linked"); } @@ -245,7 +245,7 @@ private HandshakeResult callHandlerAndReturnResult( String hostname) { HandshakeData handshakeData = new HandshakeDataImpl(channel, bedrockData != null, - bedrockData, configHolder.get(), null, hostname); + bedrockData, config, null, hostname); handshakeHandlers.callHandshakeHandlers(handshakeData); return new HandshakeResult(resultType, handshakeData, bedrockData, null); diff --git a/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java b/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java index 92c9a395..d0228921 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java +++ b/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java @@ -26,6 +26,8 @@ package org.geysermc.floodgate.util; import com.google.common.base.Joiner; +import com.google.inject.Inject; +import com.google.inject.Singleton; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; @@ -37,19 +39,18 @@ import java.util.Map; import java.util.Properties; import lombok.Getter; -import lombok.RequiredArgsConstructor; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.config.FloodgateConfigHolder; /** * Manages translations for strings in Floodgate */ -@RequiredArgsConstructor +@Singleton public final class LanguageManager { private final Map localeMappings = new HashMap<>(); - private final FloodgateConfigHolder configHolder; - private final FloodgateLogger logger; + + @Inject private FloodgateConfig config; + @Inject private FloodgateLogger logger; /** * The locale used in console and as a fallback @@ -71,24 +72,15 @@ private static String formatLocale(String locale) { } } - public boolean isLoaded() { - return logger != null && defaultLocale != null; - } - /** * Tries to load the log's locale file once a string has been requested */ + @Inject private void init() { if (!loadLocale("en_US")) {// Fallback logger.error("Failed to load the fallback language. This will likely cause errors!"); } - FloodgateConfig config = configHolder.get(); - if (config == null) { - // :thonk: - return; - } - defaultLocale = formatLocale(config.getDefaultLocale()); if (isValidLanguage(defaultLocale)) { @@ -167,14 +159,6 @@ public String getLogString(String key, Object... values) { * @return translated string or "key arg1, arg2 (etc.)" if it was not found in the given locale */ public String getString(String key, String locale, Object... values) { - if (!isLoaded()) { - init(); - // we can skip everything if the LanguageManager can't be loaded yet - if (!isLoaded()) { - return formatNotFound(key, values); - } - } - Properties properties = localeMappings.get(locale); String formatString = null; diff --git a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java index c3ba5abf..f80efeb6 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java +++ b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java @@ -26,23 +26,13 @@ package org.geysermc.floodgate; import com.google.inject.Inject; -import com.google.inject.Injector; import com.google.inject.Module; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; -import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.api.inject.PlatformInjector; -import org.geysermc.floodgate.api.logger.FloodgateLogger; public final class SpigotPlatform extends FloodgatePlatform { @Inject private JavaPlugin plugin; - @Inject - public SpigotPlatform(FloodgateApi api, PlatformInjector platformInjector, - FloodgateLogger logger, Injector injector) { - super(api, platformInjector, logger, injector); - } - @Override public boolean enable(Module... postInitializeModules) { boolean success = super.enable(postInitializeModules); diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index 5547046b..b0c45da0 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -60,6 +60,7 @@ public final class SpigotPlatformModule extends AbstractModule { @Override protected void configure() { bind(PlatformUtils.class).to(SpigotPlatformUtils.class); + bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); } @Provides @@ -68,12 +69,6 @@ public JavaPlugin javaPlugin() { return plugin; } - @Provides - @Singleton - public FloodgateLogger floodgateLogger(LanguageManager languageManager) { - return new JavaUtilFloodgateLogger(plugin.getLogger(), languageManager); - } - /* Commands / Listeners */ diff --git a/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java b/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java index 3b5dd543..f439d180 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java +++ b/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java @@ -27,17 +27,26 @@ import static org.geysermc.floodgate.util.MessageFormatter.format; -import lombok.RequiredArgsConstructor; +import com.google.inject.Inject; +import com.google.inject.Singleton; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.util.LanguageManager; import org.slf4j.Logger; -@RequiredArgsConstructor +@Singleton public final class Slf4jFloodgateLogger implements FloodgateLogger { - private final Logger logger; - private final LanguageManager languageManager; + @Inject private Logger logger; + @Inject private LanguageManager languageManager; + + @Inject + private void init(FloodgateConfig config) { + if (config.isDebug() && !logger.isDebugEnabled()) { + Configurator.setLevel(logger.getName(), Level.DEBUG); + } + } @Override public void error(String message, Object... args) { @@ -74,20 +83,6 @@ public void trace(String message, Object... args) { logger.trace(message, args); } - @Override - public void enableDebug() { - if (!logger.isDebugEnabled()) { - Configurator.setLevel(logger.getName(), Level.DEBUG); - } - } - - @Override - public void disableDebug() { - if (logger.isDebugEnabled()) { - Configurator.setLevel(logger.getName(), Level.INFO); - } - } - @Override public boolean isDebug() { return logger.isDebugEnabled(); diff --git a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java index 8678af5e..85fc7be5 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java +++ b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java @@ -56,11 +56,9 @@ import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageRegistration; import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageUtils; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.VelocityCommandUtil; import org.geysermc.floodgate.util.VelocityPlatformUtils; import org.geysermc.floodgate.util.VelocitySkinApplier; -import org.slf4j.Logger; @RequiredArgsConstructor public final class VelocityPlatformModule extends AbstractModule { @@ -70,6 +68,7 @@ public final class VelocityPlatformModule extends AbstractModule { protected void configure() { bind(CommandUtil.class).to(VelocityCommandUtil.class); bind(PlatformUtils.class).to(VelocityPlatformUtils.class); + bind(FloodgateLogger.class).to(Slf4jFloodgateLogger.class); } @Provides @@ -89,12 +88,6 @@ public CommandManager commandManager(CommandUtil commandUtil) { return commandManager; } - @Provides - @Singleton - public FloodgateLogger floodgateLogger(Logger logger, LanguageManager languageManager) { - return new Slf4jFloodgateLogger(logger, languageManager); - } - /* Commands / Listeners */ From 904c584a2a1892f7d4d881bcd98eb9942add67a3 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 9 Jul 2022 19:23:02 +0200 Subject: [PATCH 028/113] Small changes to platforms and injectors --- .../api/inject/PlatformInjector.java | 10 +- .../inject/bungee/BungeeInjector.java | 34 +++---- .../geysermc/floodgate/FloodgatePlatform.java | 21 ++-- .../floodgate/util/ReflectionUtils.java | 2 +- .../geysermc/floodgate/SpigotPlatform.java | 45 --------- .../org/geysermc/floodgate/SpigotPlugin.java | 23 +++-- .../inject/spigot/SpigotInjector.java | 95 +++++++++---------- .../inject/velocity/VelocityInjector.java | 15 ++- .../module/VelocityPlatformModule.java | 4 +- 9 files changed, 94 insertions(+), 155 deletions(-) delete mode 100644 spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java diff --git a/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java b/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java index 5fe765e5..4c28ac40 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java +++ b/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java @@ -37,10 +37,9 @@ public interface PlatformInjector { * Injects the server connection. This will allow various addons (like getting the Floodgate * data and debug mode) to work. * - * @return true if the connection has successfully been injected - * @throws Exception if something went wrong while injecting the server connection + * @throws Exception if the platform couldn't be injected */ - boolean inject() throws Exception; + void inject() throws Exception; /** * Some platforms may not be able to remove their injection process. If so, this method will @@ -56,10 +55,9 @@ default boolean canRemoveInjection() { * Removes the injection from the server. Please note that this function should only be used * internally (on plugin shutdown). This method will also remove every added addon. * - * @return true if the injection has successfully been removed - * @throws Exception if something went wrong while removing the injection + * @throws Exception if the platform injection could not be removed */ - boolean removeInjection() throws Exception; + void removeInjection() throws Exception; /** * If the server connection is currently injected. diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index 7181edd2..e6a3e964 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -49,27 +49,21 @@ public final class BungeeInjector extends CommonPlatformInjector { @Getter private boolean injected; @Override - public boolean inject() { - try { - // Can everyone just switch to Velocity please :) + public void inject() { + // Can everyone just switch to Velocity please :) - Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); + Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); - // Required in order to inject into both Geyser <-> proxy AND proxy <-> server - // (Instead of just replacing the ChannelInitializer which is only called for - // player <-> proxy) - BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( - this, ReflectionUtils.castedStaticValue(framePrepender) - ); + // Required in order to inject into both Geyser <-> proxy AND proxy <-> server + // (Instead of just replacing the ChannelInitializer which is only called for + // player <-> proxy) + BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( + this, ReflectionUtils.castedStaticValue(framePrepender) + ); - BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender); + BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender); - injected = true; - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } + injected = true; } @Override @@ -78,9 +72,9 @@ public boolean canRemoveInjection() { } @Override - public boolean removeInjection() { - logger.error("Floodgate cannot remove itself from Bungee without a reboot"); - return false; + public void removeInjection() { + throw new IllegalStateException( + "Floodgate cannot remove itself from Bungee without a reboot"); } void injectClient(Channel channel, boolean clientToProxy) { diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index 3f511d83..dfb81699 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -64,20 +64,15 @@ public void init(PacketHandlers packetHandlers, HandshakeHandlers handshakeHandl guice.getInstance(NewsChecker.class).start(); } - public boolean enable(Module... postInitializeModules) { + public void enable(Module... postInitializeModules) throws RuntimeException { if (injector == null) { - logger.error("Failed to find the platform injector!"); - return false; + throw new RuntimeException("Failed to find the platform injector!"); } try { - if (!injector.inject()) { - logger.error("Failed to inject the packet listener!"); - return false; - } + injector.inject(); } catch (Exception exception) { - logger.error("Failed to inject the packet listener!", exception); - return false; + throw new RuntimeException("Failed to inject the packet listener!", exception); } this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules)); @@ -85,8 +80,6 @@ public boolean enable(Module... postInitializeModules) { PrefixCheckTask.checkAndExecuteDelayed(config, logger); guice.getInstance(Metrics.class); - - return true; } public void disable() { @@ -94,11 +87,9 @@ public void disable() { if (injector != null && injector.canRemoveInjection()) { try { - if (!injector.removeInjection()) { - logger.error("Failed to remove the injection!"); - } + injector.removeInjection(); } catch (Exception exception) { - logger.error("Failed to remove the injection!", exception); + throw new RuntimeException("Failed to remove the injection!", exception); } } } diff --git a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java index 80352d87..dfbc9d6a 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java @@ -424,7 +424,7 @@ public static Method getMethod(Object instance, String methodName, Class... a } @Nullable - public static Method getMethod( + public static Method getMethodThatReturns( Class clazz, Class returnType, boolean declared, diff --git a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java deleted file mode 100644 index f80efeb6..00000000 --- a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlatform.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019-2022 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/Floodgate - */ - -package org.geysermc.floodgate; - -import com.google.inject.Inject; -import com.google.inject.Module; -import org.bukkit.Bukkit; -import org.bukkit.plugin.java.JavaPlugin; - -public final class SpigotPlatform extends FloodgatePlatform { - @Inject private JavaPlugin plugin; - - @Override - public boolean enable(Module... postInitializeModules) { - boolean success = super.enable(postInitializeModules); - if (!success) { - Bukkit.getPluginManager().disablePlugin(plugin); - return false; - } - return true; - } -} diff --git a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java index 6254cc17..2a5af4ee 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java +++ b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java @@ -27,6 +27,7 @@ import com.google.inject.Guice; import com.google.inject.Injector; +import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.logger.FloodgateLogger; @@ -43,7 +44,7 @@ import org.geysermc.floodgate.util.SpigotProtocolSupportListener; public final class SpigotPlugin extends JavaPlugin { - private SpigotPlatform platform; + private FloodgatePlatform platform; private Injector injector; @Override @@ -54,7 +55,7 @@ public void onLoad() { new SpigotPlatformModule(this) ); - platform = injector.getInstance(SpigotPlatform.class); + platform = injector.getInstance(FloodgatePlatform.class); long endCtm = System.currentTimeMillis(); injector.getInstance(FloodgateLogger.class) @@ -66,14 +67,18 @@ public void onEnable() { boolean usePaperListener = ReflectionUtils.getClassSilently( "com.destroystokyo.paper.event.profile.PreFillProfileEvent") != null; - platform.enable( - new SpigotCommandModule(this), - new SpigotAddonModule(), - new PluginMessageModule(), - (usePaperListener ? new PaperListenerModule() : new SpigotListenerModule()) - ); + try { + platform.enable( + new SpigotCommandModule(this), + new SpigotAddonModule(), + new PluginMessageModule(), + (usePaperListener ? new PaperListenerModule() : new SpigotListenerModule()) + ); + } catch (Exception exception) { + Bukkit.getPluginManager().disablePlugin(this); + throw exception; + } - //todo add proper support for disabling things on shutdown and enabling this on enable injector.getInstance(HandshakeHandlers.class) .addHandshakeHandler(injector.getInstance(SpigotHandshakeHandler.class)); diff --git a/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java b/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java index 9ea99b1a..2a718b0a 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java +++ b/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java @@ -31,7 +31,6 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -51,54 +50,56 @@ public final class SpigotInjector extends CommonPlatformInjector { @Override @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") - public boolean inject() throws Exception { + public void inject() throws Exception { if (isInjected()) { - return true; + return; } - if (getServerConnection() != null) { - for (Field field : serverConnection.getClass().getDeclaredFields()) { - if (field.getType() == List.class) { - field.setAccessible(true); + Object serverConnection = getServerConnection(); + if (serverConnection == null) { + throw new RuntimeException("Unable to find server connection"); + } - ParameterizedType parameterType = ((ParameterizedType) field.getGenericType()); - Type listType = parameterType.getActualTypeArguments()[0]; + for (Field field : serverConnection.getClass().getDeclaredFields()) { + if (field.getType() == List.class) { + field.setAccessible(true); - // the list we search has ChannelFuture as type - if (listType != ChannelFuture.class) { - continue; - } + ParameterizedType parameterType = ((ParameterizedType) field.getGenericType()); + Type listType = parameterType.getActualTypeArguments()[0]; - injectedFieldName = field.getName(); - List newList = new CustomList((List) field.get(serverConnection)) { - @Override - public void onAdd(Object object) { - try { - injectClient((ChannelFuture) object); - } catch (Exception exception) { - exception.printStackTrace(); - } + // the list we search has ChannelFuture as type + if (listType != ChannelFuture.class) { + continue; + } + + injectedFieldName = field.getName(); + List newList = new CustomList((List) field.get(serverConnection)) { + @Override + public void onAdd(Object object) { + try { + injectClient((ChannelFuture) object); + } catch (Exception exception) { + exception.printStackTrace(); } - }; - - // inject existing - synchronized (newList) { - for (Object object : newList) { - try { - injectClient((ChannelFuture) object); - } catch (Exception exception) { - exception.printStackTrace(); - } + } + }; + + // inject existing + synchronized (newList) { + for (Object object : newList) { + try { + injectClient((ChannelFuture) object); + } catch (Exception exception) { + exception.printStackTrace(); } } - - field.set(serverConnection, newList); - injected = true; - return true; } + + field.set(serverConnection, newList); + injected = true; + return; } } - return false; } public void injectClient(ChannelFuture future) { @@ -120,9 +121,9 @@ protected void initChannel(Channel channel) { } @Override - public boolean removeInjection() throws Exception { + public void removeInjection() { if (!isInjected()) { - return true; + return; } // remove injection from clients @@ -146,10 +147,9 @@ public boolean removeInjection() throws Exception { } injected = false; - return true; } - public Object getServerConnection() throws IllegalAccessException, InvocationTargetException { + public Object getServerConnection() { if (serverConnection != null) { return serverConnection; } @@ -158,14 +158,11 @@ public Object getServerConnection() throws IllegalAccessException, InvocationTar // method by CraftBukkit to get the instance of the MinecraftServer Object minecraftServerInstance = ReflectionUtils.invokeStatic(minecraftServer, "getServer"); - for (Method method : minecraftServer.getDeclaredMethods()) { - if (ClassNames.SERVER_CONNECTION.equals(method.getReturnType())) { - // making sure that it's a getter - if (method.getParameterTypes().length == 0) { - serverConnection = method.invoke(minecraftServerInstance); - } - } - } + Method method = ReflectionUtils.getMethodThatReturns( + minecraftServer, ClassNames.SERVER_CONNECTION, true + ); + + serverConnection = ReflectionUtils.invoke(minecraftServerInstance, method); return serverConnection; } diff --git a/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java b/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java index 1a4d43b1..4d122cf1 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java +++ b/velocity/src/main/java/org/geysermc/floodgate/inject/velocity/VelocityInjector.java @@ -36,21 +36,19 @@ import java.lang.reflect.Method; import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.inject.CommonPlatformInjector; @RequiredArgsConstructor public final class VelocityInjector extends CommonPlatformInjector { private final ProxyServer server; - private final FloodgateLogger logger; @Getter private boolean injected; @Override @SuppressWarnings("rawtypes") - public boolean inject() { + public void inject() { if (isInjected()) { - return true; + return; } Object connectionManager = getValue(server, "cm"); @@ -72,7 +70,8 @@ public boolean inject() { Method backendSetter = getMethod(backendInitializerHolder, "set", ChannelInitializer.class); invoke(backendInitializerHolder, backendSetter, new VelocityChannelInitializer(this, backendInitializer, true)); - return injected = true; + + injected = true; } @Override @@ -81,9 +80,9 @@ public boolean canRemoveInjection() { } @Override - public boolean removeInjection() { - logger.error("Floodgate cannot remove itself from Velocity without a reboot"); - return false; + public void removeInjection() { + throw new IllegalStateException( + "Floodgate cannot remove itself from Velocity without a reboot"); } @RequiredArgsConstructor diff --git a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java index 85fc7be5..b5244c3a 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java +++ b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java @@ -124,8 +124,8 @@ public SkinApplier skinApplier(ProxyServer server) { @Provides @Singleton - public CommonPlatformInjector platformInjector(ProxyServer server, FloodgateLogger logger) { - return new VelocityInjector(server, logger); + public CommonPlatformInjector platformInjector(ProxyServer server) { + return new VelocityInjector(server); } @Provides From 41de3673a7e5e926aced1f5693e1f828f65060d8 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 11 Jul 2022 11:13:37 +0200 Subject: [PATCH 029/113] Changed how post-enable messages work internally + minor other changes --- .gitignore | 97 ++++++++-------- .../floodgate/api/link/LinkRequestResult.java | 4 - .../geysermc/floodgate/FloodgatePlatform.java | 12 +- .../floodgate/config/ConfigLoader.java | 4 +- .../floodgate/config/FloodgateConfig.java | 12 +- .../floodgate/event/PostEnableEvent.java | 29 +++++ .../floodgate/util/LanguageManager.java | 22 +--- .../floodgate/util/PostEnableMessages.java | 105 ++++++++++++++++++ .../floodgate/util/PrefixCheckTask.java | 65 ----------- .../org/geysermc/floodgate/util/Utils.java | 42 ++----- 10 files changed, 221 insertions(+), 171 deletions(-) create mode 100644 core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java create mode 100644 core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java delete mode 100644 core/src/main/java/org/geysermc/floodgate/util/PrefixCheckTask.java diff --git a/.gitignore b/.gitignore index 58ae9e78..27c8ac2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all -# Edit at https://www.gitignore.io/?templates=git,java,maven,eclipse,netbeans,jetbrains+all +# Created by https://www.gitignore.io/api/git,java,gradle,eclipse,netbeans,jetbrains+all +# Edit at https://www.gitignore.io/?templates=git,gradle,maven,eclipse,netbeans,jetbrains+all ### Eclipse ### .metadata @@ -52,22 +52,19 @@ local.properties # Annotation Processing .apt_generated/ +.apt_generated_test/ # Scala IDE specific (Scala & Java development for Eclipse) .cache-main .scala_dependencies .worksheet -### Eclipse Patch ### -# Eclipse Core -.project - -# JDT-specific (Eclipse Java Development Tools) -.classpath - -# Annotation Processing -.apt_generated +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project +### Eclipse Patch ### +# Spring Boot Tooling .sts4-cache/ ### Git ### @@ -109,9 +106,10 @@ local.properties # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +replay_pid* ### JetBrains+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff @@ -121,6 +119,9 @@ hs_err_pid* .idea/**/dictionaries .idea/**/shelf +# AWS User-specific +.idea/**/aws.xml + # Generated files .idea/**/contentModel.xml @@ -141,11 +142,14 @@ hs_err_pid* # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr +.idea/artifacts +.idea/compiler.xml +.idea/jarRepositories.xml +.idea/modules.xml +.idea/*.iml +.idea/modules +*.iml +*.ipr # CMake cmake-build-*/ @@ -168,6 +172,9 @@ atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml +# SonarLint plugin +.idea/sonarlint/ + # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties @@ -181,32 +188,13 @@ fabric.properties .idea/caches/build_file_checksums.ser ### JetBrains+all Patch ### -# Ignores the whole .idea folder and all .iml files -# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. -.idea/ +.idea/* -# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 - -*.iml -modules.xml -.idea/misc.xml -*.ipr - -# Sonarlint plugin -.idea/sonarlint - -### Maven ### -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar +!.idea/codeStyles +!.idea/runConfigurations ### NetBeans ### **/nbproject/private/ @@ -218,8 +206,29 @@ dist/ nbdist/ .nb-gradle/ -# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all -gradle/ -**/.gradle/ +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# End of https://www.gitignore.io/api/git,java,gradle,eclipse,netbeans,jetbrains+all /core/src/main/resources/languages/ diff --git a/api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java b/api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java index ea7c795c..3d8fad03 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java +++ b/api/src/main/java/org/geysermc/floodgate/api/link/LinkRequestResult.java @@ -34,10 +34,6 @@ public enum LinkRequestResult { * An unknown error encountered while creating / verifying the link request. */ UNKNOWN_ERROR, - /** - * @deprecated this result isn't used. Instead the link code is returned - */ - REQUEST_CREATED, /** * The specified bedrock username is already linked to a Java account. */ diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index dfb81699..038bfe50 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -35,23 +35,21 @@ import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.link.PlayerLink; -import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.config.FloodgateConfig; +import org.geysermc.floodgate.event.PostEnableEvent; import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.module.PostInitializeModule; import org.geysermc.floodgate.news.NewsChecker; import org.geysermc.floodgate.util.Metrics; -import org.geysermc.floodgate.util.PrefixCheckTask; +import org.geysermc.floodgate.util.PostEnableMessages; public class FloodgatePlatform { private static final UUID KEY = UUID.randomUUID(); @Inject private FloodgateApi api; @Inject private PlatformInjector injector; - @Inject private FloodgateLogger logger; - @Inject private FloodgateConfig config; @Inject private Injector guice; @@ -77,9 +75,11 @@ public void enable(Module... postInitializeModules) throws RuntimeException { this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules)); - PrefixCheckTask.checkAndExecuteDelayed(config, logger); - + //todo add some kind of auto-load, as this looks kinda weird + guice.getInstance(PostEnableMessages.class); guice.getInstance(Metrics.class); + + guice.getInstance(PubSubSupport.class).publish(new PostEnableEvent()); } public void disable() { diff --git a/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java index 51272b89..e4311058 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java @@ -41,7 +41,7 @@ @Getter @RequiredArgsConstructor public final class ConfigLoader { - private final Path dataFolder; + private final Path dataDirectory; private final Class configClass; private final KeyProducer keyProducer; @@ -62,7 +62,7 @@ public T load() { ConfigUtilities utilities = ConfigUtilities.builder() - .fileCodec(PathFileCodec.of(dataFolder)) + .fileCodec(PathFileCodec.of(dataDirectory)) .configFile("config.yml") .templateReader(ResourceTemplateReader.of(getClass())) .template(templateFile) diff --git a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java index b7b6b866..4a87b0d4 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java +++ b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java @@ -52,7 +52,9 @@ public class FloodgateConfig implements GenericPostInitializeCallback= 16) { + usernamePrefix = "."; + } + return CallbackResult.ok(); } diff --git a/core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java b/core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java new file mode 100644 index 00000000..0ae55e26 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.event; + +public class PostEnableEvent { +} diff --git a/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java b/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java index d0228921..a3d659bf 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java +++ b/core/src/main/java/org/geysermc/floodgate/util/LanguageManager.java @@ -28,11 +28,7 @@ import com.google.common.base.Joiner; import com.google.inject.Inject; import com.google.inject.Singleton; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; @@ -117,21 +113,11 @@ public boolean loadLocale(String locale) { return true; } - InputStream localeStream = LanguageManager.class.getClassLoader().getResourceAsStream( - "languages/texts/" + formatLocale + ".properties"); + Properties properties = + Utils.readProperties("languages/texts/" + formatLocale + ".properties"); - // load the locale - if (localeStream != null) { - Properties localeProp = new Properties(); - - try (Reader reader = new InputStreamReader(localeStream, StandardCharsets.UTF_8)) { - localeProp.load(reader); - } catch (Exception e) { - throw new AssertionError("Failed to load Floodgate locale", e); - } - - // insert the locale into the mappings - localeMappings.put(formatLocale, localeProp); + if (properties != null) { + localeMappings.put(formatLocale, properties); return true; } diff --git a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java new file mode 100644 index 00000000..b324f4bd --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import com.google.inject.Inject; +import java.util.ArrayList; +import java.util.List; +import net.engio.mbassy.listener.Handler; +import net.engio.mbassy.listener.Listener; +import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.config.FloodgateConfig; +import org.geysermc.floodgate.event.PostEnableEvent; + +@Listener +public final class PostEnableMessages { + private final List messages = new ArrayList<>(); + + @Inject private FloodgateConfig config; + @Inject private FloodgateLogger logger; + + public void add(String[] message, Object... args) { + StringBuilder builder = new StringBuilder(); + + builder.append("\n**********************************\n"); + for (String part : message) { + builder.append("* ").append(part).append('\n'); + } + builder.append("**********************************"); + + messages.add(MessageFormatter.format(builder.toString(), args)); + } + + @Inject + private void init() { + registerPrefixMessages(); + } + + private void registerPrefixMessages() { + String prefix = config.getRawUsernamePrefix(); + + if (prefix.isEmpty()) { + add(new String[]{ + "You specified an empty prefix in your Floodgate config for Bedrock players!", + "Should a Java player join and a Bedrock player join with the same username, unwanted results and conflicts will happen!", + "We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *" + }); + } else if (!Utils.isUniquePrefix(prefix)) { + add(new String[]{ + "The prefix you entered in your Floodgate config ({}) could lead to username conflicts!", + "Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!", + "We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *" + }, prefix, prefix, prefix, prefix); + } + + if (prefix.length() >= 16) { + add(new String[]{ + "The prefix you entered in your Floodgate config ({}) is longer than a Java username can be!", + "Because of this, we reset the prefix to the default Floodgate prefix (.)" + }, prefix); + } else if (prefix.length() > 2) { + // we only have to warn them if we haven't replaced the prefix + add(new String[]{ + "The prefix you entered in your Floodgate config ({}) is long! ({} characters)", + "A prefix is there to prevent username conflicts. However, a long prefix makes the chance of username conflicts higher.", + "We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *" + }, prefix, prefix.length()); + } + } + + @Handler + public void onPostEnable(PostEnableEvent ignored) { + new Thread(() -> { + // normally proxies don't have a lot of plugins, so proxies don't need to sleep as long + try { + Thread.sleep(config.isProxy() ? 2000 : 5000); + } catch (InterruptedException ignored1) { + } + + messages.forEach(logger::warn); + }).start(); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/util/PrefixCheckTask.java b/core/src/main/java/org/geysermc/floodgate/util/PrefixCheckTask.java deleted file mode 100644 index 4631171f..00000000 --- a/core/src/main/java/org/geysermc/floodgate/util/PrefixCheckTask.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019-2022 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/Floodgate - */ - -package org.geysermc.floodgate.util; - -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.config.FloodgateConfig; - -public final class PrefixCheckTask { - public static void checkAndExecuteDelayed(FloodgateConfig config, FloodgateLogger logger) { - if (Utils.isUniquePrefix(config.getUsernamePrefix())) { - return; - } - - new Thread(() -> { - // normally proxies don't have a lot of plugins, so proxies don't need to sleep as long - try { - Thread.sleep(config.isProxy() ? 1000 : 2000); - } catch (InterruptedException ignored) { - } - - if (config.getUsernamePrefix().isEmpty()) { - logger.warn("\n" + - "**********************************\n" + - "* You specified an empty prefix in your Floodgate config for Bedrock players!\n" + - "* Should a Java player join and a Bedrock player join with the same username, unwanted results and conflicts will happen!\n" + - "* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *\n" + - "**********************************"); - return; - } - - logger.warn( - "\n" + - "**********************************\n" + - "* The prefix you entered in your Floodgate config ({}) could lead to username conflicts!\n" + - "* Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!\n" + - "* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *\n" + - "**********************************", - config.getUsernamePrefix(), config.getUsernamePrefix(), - config.getUsernamePrefix(), config.getUsernamePrefix()); - }).start(); - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/util/Utils.java b/core/src/main/java/org/geysermc/floodgate/util/Utils.java index d6efda3a..9d2d93c7 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Utils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Utils.java @@ -28,18 +28,10 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.PrintWriter; -import java.io.Reader; import java.io.StringWriter; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.UUID; @@ -47,7 +39,7 @@ import java.util.regex.Pattern; public class Utils { - private static final Pattern NON_UNIQUE_PREFIX = Pattern.compile("^[a-zA-Z0-9_]{0,16}$"); + private static final Pattern NON_UNIQUE_PREFIX = Pattern.compile("^\\w{0,16}$"); private static final Pattern DATABASE_NAME = Pattern.compile(Constants.DATABASE_NAME_FORMAT); /** @@ -66,33 +58,21 @@ public static void removeHandler(ChannelPipeline pipeline, String handler) { } } - public static List readAllLines(String resourcePath) throws IOException { - InputStream stream = Utils.class.getClassLoader().getResourceAsStream(resourcePath); - try (BufferedReader reader = newBufferedReader(stream, StandardCharsets.UTF_8)) { - List result = new ArrayList<>(); - for (; ; ) { - String line = reader.readLine(); - if (line == null) { - break; - } - result.add(line); - } - return result; - } - } - - public static BufferedReader newBufferedReader(InputStream inputStream, Charset charset) { - CharsetDecoder decoder = charset.newDecoder(); - Reader reader = new InputStreamReader(inputStream, decoder); - return new BufferedReader(reader); - } - + /** + * Reads a properties resource file + * @param resourceFile the resource file to read + * @return the properties file if the resource exists, otherwise null + * @throws AssertionError if something went wrong while readin the resource file + */ public static Properties readProperties(String resourceFile) { Properties properties = new Properties(); try (InputStream is = Utils.class.getClassLoader().getResourceAsStream(resourceFile)) { + if (is == null) { + return null; + } properties.load(is); } catch (IOException e) { - e.printStackTrace(); + throw new AssertionError("Failed to read properties file", e); } return properties; } From 450eeed2a371b6c226087d52f168a11533e4c697 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 11 Jul 2022 12:36:18 +0200 Subject: [PATCH 030/113] Deprecate handshake handlers and player properties --- .../geysermc/floodgate/api/handshake/HandshakeData.java | 1 + .../floodgate/api/handshake/HandshakeHandler.java | 1 + .../floodgate/api/handshake/HandshakeHandlers.java | 7 +++++++ .../geysermc/floodgate/api/player/FloodgatePlayer.java | 8 ++++++++ .../org/geysermc/floodgate/api/player/PropertyKey.java | 1 + 5 files changed, 18 insertions(+) diff --git a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java index 44eb1c3c..1ebc6525 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java +++ b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java @@ -37,6 +37,7 @@ * server. Note that at the time I'm writing this that the HandshakeData is created after requesting * the player link. So the link is present here, if applicable. */ +@Deprecated public interface HandshakeData { /** * Returns the Channel holding the connection between the client and the server. diff --git a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java index 2aca5498..8ce06253 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java +++ b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java @@ -34,6 +34,7 @@ * HandshakeData#isFloodgatePlayer()} will be false and Floodgate related methods will return null * for Java players */ +@Deprecated @FunctionalInterface public interface HandshakeHandler { /** diff --git a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java index ef19b545..088ac9af 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java +++ b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java @@ -25,6 +25,13 @@ package org.geysermc.floodgate.api.handshake; +/** + * @deprecated This system has been deprecated and will not be available in the new API that will be + * introduced when Geyser will include Floodgate (and thus will have some common base API). + *
+ * It might be replaced with an event (probably internal), but that isn't certain yet. + */ +@Deprecated public interface HandshakeHandlers { /** * Register a custom handshake handler. This can be used to check and edit the player during the diff --git a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java index c69578c5..6205da0d 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java +++ b/api/src/main/java/org/geysermc/floodgate/api/player/FloodgatePlayer.java @@ -143,20 +143,28 @@ default boolean transfer(String address, int port) { return FloodgateApi.getInstance().transferPlayer(getCorrectUniqueId(), address, port); } + @Deprecated boolean hasProperty(PropertyKey key); + @Deprecated boolean hasProperty(String key); + @Deprecated T getProperty(PropertyKey key); + @Deprecated T getProperty(String key); + @Deprecated T removeProperty(PropertyKey key); + @Deprecated T removeProperty(String key); + @Deprecated T addProperty(PropertyKey key, Object value); + @Deprecated T addProperty(String key, Object value); /** diff --git a/api/src/main/java/org/geysermc/floodgate/api/player/PropertyKey.java b/api/src/main/java/org/geysermc/floodgate/api/player/PropertyKey.java index 04e1d4d0..62bebaf8 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/player/PropertyKey.java +++ b/api/src/main/java/org/geysermc/floodgate/api/player/PropertyKey.java @@ -28,6 +28,7 @@ import lombok.Getter; @Getter +@Deprecated public class PropertyKey { /** * Socket Address returns the InetSocketAddress of the Bedrock player From 4eb60abe0711149c75d85c83a5f5460d6303a8ac Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 12 Jul 2022 14:02:36 +0200 Subject: [PATCH 031/113] Added auto-binding --- ap/build.gradle.kts | 0 .../floodgate/ap/AutoBindProcessor.java | 38 +++ .../geysermc/floodgate/ap/ClassProcessor.java | 221 ++++++++++++++++++ .../javax.annotation.processing.Processor | 1 + core/build.gradle.kts | 3 + .../geysermc/floodgate/FloodgatePlatform.java | 19 +- .../floodgate/module/AutoBindModule.java | 39 ++++ .../floodgate/module/CommonModule.java | 11 +- .../geysermc/floodgate/news/NewsChecker.java | 3 + .../org/geysermc/floodgate/util/AutoBind.java | 38 +++ .../org/geysermc/floodgate/util/Metrics.java | 1 + .../floodgate/util/PostEnableMessages.java | 1 + .../org/geysermc/floodgate/util/Utils.java | 43 ++++ settings.gradle.kts | 1 + 14 files changed, 403 insertions(+), 16 deletions(-) create mode 100644 ap/build.gradle.kts create mode 100644 ap/src/main/java/org/geysermc/floodgate/ap/AutoBindProcessor.java create mode 100644 ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java create mode 100644 ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor create mode 100644 core/src/main/java/org/geysermc/floodgate/module/AutoBindModule.java create mode 100644 core/src/main/java/org/geysermc/floodgate/util/AutoBind.java diff --git a/ap/build.gradle.kts b/ap/build.gradle.kts new file mode 100644 index 00000000..e69de29b diff --git a/ap/src/main/java/org/geysermc/floodgate/ap/AutoBindProcessor.java b/ap/src/main/java/org/geysermc/floodgate/ap/AutoBindProcessor.java new file mode 100644 index 00000000..52bd93d2 --- /dev/null +++ b/ap/src/main/java/org/geysermc/floodgate/ap/AutoBindProcessor.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.ap; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +@SupportedAnnotationTypes("*") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class AutoBindProcessor extends ClassProcessor { + public AutoBindProcessor() { + super("org.geysermc.floodgate.util.AutoBind"); + } +} diff --git a/ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java b/ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java new file mode 100644 index 00000000..3758711a --- /dev/null +++ b/ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.ap; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +/* + * Copied from Geyser + */ +public class ClassProcessor extends AbstractProcessor { + private final String annotationClassName; + + private Path outputPath; + + private final Set locations = new HashSet<>(); + + public ClassProcessor(String annotationClassName) { + this.annotationClassName = annotationClassName; + } + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + + processingEnv.getMessager().printMessage( + Kind.NOTE, "Initializing processor " + annotationClassName + ); + + String outputFile = processingEnv.getOptions().get("metadataOutputFile"); + if (outputFile != null && !outputFile.isEmpty()) { + outputPath = Paths.get(outputFile); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + if (!roundEnv.errorRaised()) { + complete(); + } + + return false; + } + + if (!contains(annotations, annotationClassName)) { + return false; + } + + for (Element element : roundEnv.getRootElements()) { + if (element.getKind() != ElementKind.CLASS) { + continue; + } + + if (!contains(element.getAnnotationMirrors(), annotationClassName)) { + continue; + } + + TypeElement typeElement = (TypeElement) element; + locations.add(typeElement.getQualifiedName().toString()); + } + return false; + } + + public boolean contains(Collection elements, String className) { + if (elements.isEmpty()) { + return false; + } + + for (TypeElement element : elements) { + if (element.getQualifiedName().contentEquals(className)) { + return true; + } + } + + return false; + } + + public boolean contains(List elements, String className) { + if (elements.isEmpty()) { + return false; + } + + for (AnnotationMirror element : elements) { + if (element.getAnnotationType().toString().equals(className)) { + return true; + } + } + + return false; + } + + public void complete() { + // Read existing annotation list and verify each class still has this annotation + try (BufferedReader reader = createReader()) { + if (reader != null) { + reader.lines().forEach(canonicalName -> { + if (!locations.contains(canonicalName)) { + + TypeElement element = + processingEnv.getElementUtils().getTypeElement(canonicalName); + + if (element != null && element.getKind() == ElementKind.CLASS && + contains(element.getAnnotationMirrors(), annotationClassName)) { + locations.add(canonicalName); + } + } + }); + } + } catch (IOException e) { + e.printStackTrace(); + } + + if (!locations.isEmpty()) { + try (BufferedWriter writer = createWriter()) { + for (String location : locations) { + writer.write(location); + writer.newLine(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } else { + processingEnv.getMessager().printMessage(Kind.NOTE, + "Did not find any classes annotated with " + annotationClassName + ); + } + + processingEnv.getMessager().printMessage( + Kind.NOTE, "Completed processing for " + annotationClassName + ); + } + + private BufferedReader createReader() throws IOException { + if (outputPath != null) { + processingEnv.getMessager().printMessage(Kind.NOTE, + "Reading existing " + annotationClassName + " list from " + outputPath + ); + + return Files.newBufferedReader(outputPath); + } + + FileObject obj = processingEnv.getFiler().getResource( + StandardLocation.CLASS_OUTPUT, "", annotationClassName + ); + + if (obj != null) { + processingEnv.getMessager().printMessage( + Kind.NOTE, + "Reading existing " + annotationClassName + " list from " + obj.toUri() + ); + + try { + return new BufferedReader(obj.openReader(false)); + } catch (NoSuchFileException ignored) {} + } + return null; + } + + private BufferedWriter createWriter() throws IOException { + if (outputPath != null) { + processingEnv.getMessager().printMessage( + Kind.NOTE, "Writing " + annotationClassName + " to " + outputPath + ); + + return Files.newBufferedWriter(outputPath); + } + + FileObject obj = processingEnv.getFiler().createResource( + StandardLocation.CLASS_OUTPUT, "", annotationClassName + ); + + processingEnv.getMessager().printMessage( + Kind.NOTE, "Writing " + annotationClassName + " to " + obj.toUri() + ); + + return new BufferedWriter(obj.openWriter()); + } +} diff --git a/ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..53b2e379 --- /dev/null +++ b/ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +org.geysermc.floodgate.ap.AutoBindProcessor \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 258d98c5..c3b49264 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -8,6 +8,9 @@ dependencies { api(projects.api) api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion) + compileOnly(projects.ap) + annotationProcessor(projects.ap) + api("com.google.inject", "guice", Versions.guiceVersion) api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion) api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion) diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index 038bfe50..f38b99e3 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -39,27 +39,22 @@ import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.event.PostEnableEvent; import org.geysermc.floodgate.event.ShutdownEvent; -import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.module.PostInitializeModule; -import org.geysermc.floodgate.news.NewsChecker; -import org.geysermc.floodgate.util.Metrics; -import org.geysermc.floodgate.util.PostEnableMessages; public class FloodgatePlatform { private static final UUID KEY = UUID.randomUUID(); - @Inject private FloodgateApi api; @Inject private PlatformInjector injector; @Inject private FloodgateConfig config; @Inject private Injector guice; @Inject - public void init(PacketHandlers packetHandlers, HandshakeHandlers handshakeHandlers) { - PlayerLink link = guice.getInstance(PlayerLinkLoader.class).load(); - + public void init( + FloodgateApi api, + PlayerLink link, + PacketHandlers packetHandlers, + HandshakeHandlers handshakeHandlers) { InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY); - - guice.getInstance(NewsChecker.class).start(); } public void enable(Module... postInitializeModules) throws RuntimeException { @@ -75,10 +70,6 @@ public void enable(Module... postInitializeModules) throws RuntimeException { this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules)); - //todo add some kind of auto-load, as this looks kinda weird - guice.getInstance(PostEnableMessages.class); - guice.getInstance(Metrics.class); - guice.getInstance(PubSubSupport.class).publish(new PostEnableEvent()); } diff --git a/core/src/main/java/org/geysermc/floodgate/module/AutoBindModule.java b/core/src/main/java/org/geysermc/floodgate/module/AutoBindModule.java new file mode 100644 index 00000000..1c2933de --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/module/AutoBindModule.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.module; + +import com.google.inject.AbstractModule; +import org.geysermc.floodgate.util.AutoBind; +import org.geysermc.floodgate.util.Utils; + +public class AutoBindModule extends AbstractModule { + @Override + protected void configure() { + for (Class clazz : Utils.getGeneratedClassesForAnnotation(AutoBind.class)) { + bind(clazz).asEagerSingleton(); + } + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 3e15eb1a..475f39e6 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -44,6 +44,7 @@ import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.inject.PlatformInjector; +import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -56,7 +57,7 @@ import org.geysermc.floodgate.crypto.KeyProducer; import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher; import org.geysermc.floodgate.inject.CommonPlatformInjector; -import org.geysermc.floodgate.news.NewsChecker; +import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.packet.PacketHandlersImpl; import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; @@ -92,7 +93,7 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { bind(PacketHandlers.class).to(PacketHandlersImpl.class); bind(PacketHandlersImpl.class).asEagerSingleton(); - bind(NewsChecker.class).in(Singleton.class); + install(new AutoBindModule()); } @Provides @@ -101,6 +102,12 @@ public FloodgateConfig floodgateConfig(ConfigLoader configLoader) { return configLoader.load(); } + @Provides + @Singleton + public PlayerLink playerLink(PlayerLinkLoader linkLoader) { + return linkLoader.load(); + } + @Provides @Singleton public KeyProducer keyProducer() { diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index 62be4469..4ed98702 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -46,10 +46,12 @@ import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.CheckAfterData; import org.geysermc.floodgate.platform.command.CommandUtil; +import org.geysermc.floodgate.util.AutoBind; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.HttpClient; import org.geysermc.floodgate.util.HttpClient.HttpResponse; +@AutoBind @Listener public class NewsChecker { private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); @@ -71,6 +73,7 @@ public class NewsChecker { private boolean firstCheck; + @Inject public void start() { executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES); } diff --git a/core/src/main/java/org/geysermc/floodgate/util/AutoBind.java b/core/src/main/java/org/geysermc/floodgate/util/AutoBind.java new file mode 100644 index 00000000..6c1eec2e --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/util/AutoBind.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Automatically binds an instance of itself as an eager singleton during the post-initialise stage + * of the FloodgatePlatform. Add the annotation to a class, and it should automatically create an + * instance and inject it for you. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface AutoBind { +} diff --git a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java index 008d215e..474d6e7a 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java @@ -44,6 +44,7 @@ import org.geysermc.floodgate.config.FloodgateConfig.MetricsConfig; import org.geysermc.floodgate.platform.util.PlatformUtils; +@AutoBind public final class Metrics { private final MetricsBase metricsBase; diff --git a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java index b324f4bd..a8628a56 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java +++ b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java @@ -34,6 +34,7 @@ import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.event.PostEnableEvent; +@AutoBind @Listener public final class PostEnableMessages { private final List messages = new ArrayList<>(); diff --git a/core/src/main/java/org/geysermc/floodgate/util/Utils.java b/core/src/main/java/org/geysermc/floodgate/util/Utils.java index 9d2d93c7..c1765cbf 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Utils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Utils.java @@ -28,15 +28,20 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.annotation.Annotation; import java.util.Locale; import java.util.Properties; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class Utils { private static final Pattern NON_UNIQUE_PREFIX = Pattern.compile("^\\w{0,16}$"); @@ -131,4 +136,42 @@ public static CompletableFuture failedFuture(Throwable ex) { future.completeExceptionally(ex); return future; } + + /** + * Returns a set of all the classes that are annotated by a given annotation. + * Keep in mind that these are from a set of generated annotations generated + * at compile time by the annotation processor, meaning that arbitrary annotations + * cannot be passed into this method and expected to get a set of classes back. + * + * @param annotationClass the annotation class + * @return a set of all the classes annotated by the given annotation + */ + public static Set> getGeneratedClassesForAnnotation(Class annotationClass) { + return getGeneratedClassesForAnnotation(annotationClass.getName()); + } + + /** + * Returns a set of all the classes that are annotated by a given annotation. + * Keep in mind that these are from a set of generated annotations generated + * at compile time by the annotation processor, meaning that arbitrary annotations + * cannot be passed into this method and expected to have a set of classes + * returned back. + * + * @param input the fully qualified name of the annotation + * @return a set of all the classes annotated by the given annotation + */ + public static Set> getGeneratedClassesForAnnotation(String input) { + try (InputStream annotatedClass = Utils.class.getClassLoader().getResourceAsStream(input); + BufferedReader reader = new BufferedReader(new InputStreamReader(annotatedClass))) { + return reader.lines().map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException ex) { + throw new RuntimeException("Failed to find class for annotation " + input, ex); + } + }).collect(Collectors.toSet()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 7df9d09c..4a44a9d9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -51,6 +51,7 @@ pluginManagement { rootProject.name = "floodgate-parent" include(":api") +include(":ap") include(":core") include(":bungee") include(":spigot") From 4f361120d1d6dfe878f725ee3e91505583e5b94e Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 10 Aug 2022 22:52:25 +0200 Subject: [PATCH 032/113] Update Geyser common and Cumulus --- build-logic/src/main/kotlin/Versions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 740288d8..d6dbe684 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,8 +24,8 @@ */ object Versions { - const val geyserVersion = "2.0.4-SNAPSHOT" - const val cumulusVersion = "1.1" + const val geyserVersion = "2.0.7-SNAPSHOT" + const val cumulusVersion = "1.1.1" const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" From e990f2b948e3dc27ef169bbd694af06229dc9e36 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 13 Aug 2022 22:59:52 +0200 Subject: [PATCH 033/113] Switched event library --- api/build.gradle.kts | 1 + build-logic/src/main/kotlin/Versions.kt | 2 +- core/build.gradle.kts | 1 - .../geysermc/floodgate/FloodgatePlatform.java | 6 +-- .../geysermc/floodgate/event/EventBus.java | 53 +++++++++++++++++++ .../floodgate/event/EventSubscriber.java | 46 ++++++++++++++++ .../event/util/ListenerAnnotationMatcher.java | 2 +- .../floodgate/link/CommonPlayerLink.java | 6 +-- .../floodgate/module/CommonModule.java | 10 ++-- .../geysermc/floodgate/news/NewsChecker.java | 6 +-- .../geysermc/floodgate/util/HttpClient.java | 6 +-- .../floodgate/util/PostEnableMessages.java | 6 +-- 12 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 core/src/main/java/org/geysermc/floodgate/event/EventBus.java create mode 100644 core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 0bd75df1..09fb2163 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -1,6 +1,7 @@ dependencies { api("org.geysermc", "common", Versions.geyserVersion) api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) + api("org.geysermc.event", "events", Versions.eventsVersion) compileOnly("io.netty", "netty-transport", Versions.nettyVersion) } diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 9e3f4880..54aaaf74 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -26,6 +26,7 @@ object Versions { const val geyserVersion = "2.0.4-SNAPSHOT" const val cumulusVersion = "1.1" + const val eventsVersion = "1.0-SNAPSHOT" const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" @@ -34,7 +35,6 @@ object Versions { const val snakeyamlVersion = "1.28" const val cloudVersion = "1.5.0" const val bstatsVersion = "3.0.0" - const val mbassadorVersion = "1.3.2" const val javaWebsocketVersion = "1.5.2" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 258d98c5..02fec9dd 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -15,7 +15,6 @@ dependencies { api("cloud.commandframework", "cloud-core", Versions.cloudVersion) api("org.yaml", "snakeyaml", Versions.snakeyamlVersion) api("org.bstats", "bstats-base", Versions.bstatsVersion) - api("net.engio", "mbassador", Versions.mbassadorVersion) } // present on all platforms diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index 038bfe50..7036223c 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -29,7 +29,6 @@ import com.google.inject.Injector; import com.google.inject.Module; import java.util.UUID; -import net.engio.mbassy.bus.common.PubSubSupport; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.InstanceHolder; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; @@ -37,6 +36,7 @@ import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.config.FloodgateConfig; +import org.geysermc.floodgate.event.EventBus; import org.geysermc.floodgate.event.PostEnableEvent; import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.link.PlayerLinkLoader; @@ -79,11 +79,11 @@ public void enable(Module... postInitializeModules) throws RuntimeException { guice.getInstance(PostEnableMessages.class); guice.getInstance(Metrics.class); - guice.getInstance(PubSubSupport.class).publish(new PostEnableEvent()); + guice.getInstance(EventBus.class).fire(new PostEnableEvent()); } public void disable() { - guice.getInstance(PubSubSupport.class).publish(new ShutdownEvent()); + guice.getInstance(EventBus.class).fire(new ShutdownEvent()); if (injector != null && injector.canRemoveInjection()) { try { diff --git a/core/src/main/java/org/geysermc/floodgate/event/EventBus.java b/core/src/main/java/org/geysermc/floodgate/event/EventBus.java new file mode 100644 index 00000000..be768c51 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/event/EventBus.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.event; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import org.geysermc.event.bus.impl.EventBusImpl; +import org.geysermc.event.subscribe.Subscribe; +import org.geysermc.event.subscribe.Subscriber; + +@SuppressWarnings("unchecked") +public final class EventBus extends EventBusImpl> { + @Override + protected > B makeSubscription( + Class eventClass, + Subscribe subscribe, + H listener, + BiConsumer handler) { + return (B) new EventSubscriber<>( + eventClass, subscribe.postOrder(), subscribe.ignoreCancelled(), listener, handler + ); + } + + @Override + protected > B makeSubscription( + Class eventClass, + Consumer handler) { + return (B) new EventSubscriber<>(eventClass, handler); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java b/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java new file mode 100644 index 00000000..1ac57cf7 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.event; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import org.geysermc.event.PostOrder; +import org.geysermc.event.subscribe.impl.SubscriberImpl; + +public final class EventSubscriber extends SubscriberImpl { + EventSubscriber(Class eventClass, Consumer handler) { + super(eventClass, handler); + } + + EventSubscriber( + Class eventClass, + PostOrder postOrder, + boolean ignoreCancelled, + H handlerInstance, + BiConsumer handler) { + super(eventClass, postOrder, ignoreCancelled, handlerInstance, handler); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java b/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java index 614a6a52..e0881e23 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java +++ b/core/src/main/java/org/geysermc/floodgate/event/util/ListenerAnnotationMatcher.java @@ -27,7 +27,7 @@ import com.google.inject.TypeLiteral; import com.google.inject.matcher.AbstractMatcher; -import net.engio.mbassy.listener.Listener; +import org.geysermc.event.Listener; public class ListenerAnnotationMatcher extends AbstractMatcher> { @Override diff --git a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java index 29c9a4ea..c683c3e3 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java +++ b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java @@ -34,8 +34,8 @@ import java.util.concurrent.Executors; import lombok.AccessLevel; import lombok.Getter; -import net.engio.mbassy.listener.Handler; -import net.engio.mbassy.listener.Listener; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.link.LinkRequest; import org.geysermc.floodgate.api.link.PlayerLink; @@ -107,7 +107,7 @@ public void stop() { executorService.shutdown(); } - @Handler + @Subscribe public void onShutdown(ShutdownEvent ignored) { stop(); } diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 3e15eb1a..27d39540 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -36,9 +36,6 @@ import io.netty.util.AttributeKey; import java.nio.file.Path; import lombok.RequiredArgsConstructor; -import net.engio.mbassy.bus.MBassador; -import net.engio.mbassy.bus.common.PubSubSupport; -import net.engio.mbassy.bus.error.IPublicationErrorHandler.ConsoleLogger; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi; @@ -54,6 +51,7 @@ import org.geysermc.floodgate.crypto.Base64Topping; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; +import org.geysermc.floodgate.event.EventBus; import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher; import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.news.NewsChecker; @@ -67,17 +65,17 @@ @RequiredArgsConstructor public class CommonModule extends AbstractModule { - private final PubSubSupport eventBus = new MBassador<>(new ConsoleLogger(true)); + private final EventBus eventBus = new EventBus(); private final Path dataDirectory; @Override protected void configure() { - bind(PubSubSupport.class).toInstance(eventBus); + bind(EventBus.class).toInstance(eventBus); // register every class that has the Listener annotation bindListener(new ListenerAnnotationMatcher(), new TypeListener() { @Override public void hear(TypeLiteral type, TypeEncounter encounter) { - encounter.register((InjectionListener) eventBus::subscribe); + encounter.register((InjectionListener) eventBus::register); } }); diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index 62be4469..88b42da7 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -37,8 +37,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import net.engio.mbassy.listener.Handler; -import net.engio.mbassy.listener.Listener; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.command.util.Permission; import org.geysermc.floodgate.event.ShutdownEvent; @@ -206,7 +206,7 @@ public void shutdown() { executorService.shutdown(); } - @Handler + @Subscribe public void onShutdown(ShutdownEvent ignored) { shutdown(); } diff --git a/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java index c03fd49e..e665025f 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java +++ b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java @@ -37,10 +37,10 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; -import net.engio.mbassy.listener.Handler; -import net.engio.mbassy.listener.Listener; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.event.ShutdownEvent; // resources are properly closed and ignoring the original stack trace is intended @@ -162,7 +162,7 @@ private InputStreamReader createReader(HttpURLConnection connection) { return null; } - @Handler + @Subscribe public void onShutdown(ShutdownEvent ignored) { executorService.shutdown(); } diff --git a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java index b324f4bd..94275014 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java +++ b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java @@ -28,8 +28,8 @@ import com.google.inject.Inject; import java.util.ArrayList; import java.util.List; -import net.engio.mbassy.listener.Handler; -import net.engio.mbassy.listener.Listener; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.event.PostEnableEvent; @@ -90,7 +90,7 @@ private void registerPrefixMessages() { } } - @Handler + @Subscribe public void onPostEnable(PostEnableEvent ignored) { new Thread(() -> { // normally proxies don't have a lot of plugins, so proxies don't need to sleep as long From 7e930afcefa9a73d4684368ed724f16c3ce1b7d8 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 30 Aug 2022 11:54:26 +0200 Subject: [PATCH 034/113] Fixed a circular dependency issue when a locale couldn't be found --- .../kotlin/floodgate.shadow-conventions.gradle.kts | 5 +++++ .../floodgate/module/BungeePlatformModule.java | 3 +++ .../floodgate/logger/JavaUtilFloodgateLogger.java | 12 +++++++++--- .../floodgate/module/SpigotPlatformModule.java | 3 +++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts index bf3de089..7f342d8d 100644 --- a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts @@ -31,6 +31,11 @@ tasks { // for example Velocity, the relocation will be gone for Velocity) addRelocations(project, sJar) } + + val destinationDir = System.getenv("DESTINATION_DIRECTORY"); + if (destinationDir != null) { + destinationDirectory.set(file(destinationDir)) + } } named("build") { dependsOn(shadowJar) diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java index b8543417..e66fc138 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java +++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java @@ -32,6 +32,8 @@ import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.name.Named; +import com.google.inject.name.Names; +import java.util.logging.Logger; import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.Listener; @@ -66,6 +68,7 @@ public final class BungeePlatformModule extends AbstractModule { @Override protected void configure() { bind(PlatformUtils.class).to(BungeePlatformUtils.class); + bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger()); bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); } diff --git a/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java b/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java index 5940bb3a..97f1af3f 100644 --- a/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java +++ b/core/src/main/java/org/geysermc/floodgate/logger/JavaUtilFloodgateLogger.java @@ -28,18 +28,24 @@ import static org.geysermc.floodgate.util.MessageFormatter.format; import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import java.util.logging.Level; import java.util.logging.Logger; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.util.LanguageManager; +@Singleton public final class JavaUtilFloodgateLogger implements FloodgateLogger { - @Inject private Logger logger; - @Inject private LanguageManager languageManager; + @Inject + @Named("logger") + private Logger logger; + private LanguageManager languageManager; @Inject - private void init(FloodgateConfig config) { + private void init(LanguageManager languageManager, FloodgateConfig config) { + this.languageManager = languageManager; if (config.isDebug()) { logger.setLevel(Level.ALL); } diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index b0c45da0..1654badb 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -29,6 +29,8 @@ import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.name.Named; +import com.google.inject.name.Names; +import java.util.logging.Logger; import lombok.RequiredArgsConstructor; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; @@ -60,6 +62,7 @@ public final class SpigotPlatformModule extends AbstractModule { @Override protected void configure() { bind(PlatformUtils.class).to(SpigotPlatformUtils.class); + bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger()); bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); } From eca042dc820e6820c3be669ea9c0b15ab5362593 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 30 Aug 2022 13:25:09 +0200 Subject: [PATCH 035/113] Simplified plugin message channel logic --- .../BungeePluginMessageUtils.java | 20 +++--------------- .../pluginmessage/PluginMessageChannel.java | 8 +++---- .../pluginmessage/channel/FormChannel.java | 9 +++----- .../pluginmessage/channel/PacketChannel.java | 13 +++++++----- .../pluginmessage/channel/SkinChannel.java | 13 +++++------- .../channel/TransferChannel.java | 11 ++++------ .../VelocityPluginMessageUtils.java | 21 +++---------------- 7 files changed, 29 insertions(+), 66 deletions(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageUtils.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageUtils.java index 921ddf23..178657b0 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageUtils.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeePluginMessageUtils.java @@ -53,21 +53,6 @@ public void onPluginMessage(PluginMessageEvent event) { return; } - UUID targetUuid = null; - String targetUsername = null; - Identity targetIdentity = Identity.UNKNOWN; - - Connection target = event.getReceiver(); - if (target instanceof ProxiedPlayer) { - ProxiedPlayer player = (ProxiedPlayer) target; - targetUuid = player.getUniqueId(); - targetUsername = player.getName(); - targetIdentity = Identity.PLAYER; - - } else if (target instanceof ServerConnection) { - targetIdentity = Identity.SERVER; - } - UUID sourceUuid = null; String sourceUsername = null; Identity sourceIdentity = Identity.UNKNOWN; @@ -83,8 +68,9 @@ public void onPluginMessage(PluginMessageEvent event) { sourceIdentity = Identity.SERVER; } - Result result = channel.handleProxyCall(event.getData(), targetUuid, targetUsername, - targetIdentity, sourceUuid, sourceUsername, sourceIdentity); + Result result = channel.handleProxyCall( + event.getData(), sourceUuid, sourceUsername, sourceIdentity + ); event.setCancelled(!result.isAllowed()); diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannel.java index 28f8c068..067edd31 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannel.java @@ -36,14 +36,12 @@ public interface PluginMessageChannel { Result handleProxyCall( byte[] data, - UUID targetUuid, - String targetUsername, - Identity targetIdentity, UUID sourceUuid, String sourceUsername, - Identity sourceIdentity); + Identity sourceIdentity + ); - Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername); + Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername); @Getter @RequiredArgsConstructor(access = AccessLevel.PRIVATE) diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java index 9d48b732..b12ec325 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java @@ -56,13 +56,10 @@ public String getIdentifier() { @Override public Result handleProxyCall( byte[] data, - UUID targetUuid, - String targetUsername, - Identity targetIdentity, UUID sourceUuid, String sourceUsername, - Identity sourceIdentity) { - + Identity sourceIdentity + ) { if (sourceIdentity == Identity.SERVER) { // send it to the client return Result.forward(); @@ -89,7 +86,7 @@ public Result handleProxyCall( } @Override - public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) { + public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) { callResponseConsumer(data); return Result.handled(); } diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/PacketChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/PacketChannel.java index a6da65c5..2296f35e 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/PacketChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/PacketChannel.java @@ -40,23 +40,26 @@ public String getIdentifier() { } @Override - public Result handleProxyCall(byte[] data, UUID targetUuid, String targetUsername, - Identity targetIdentity, UUID sourceUuid, String sourceUsername, - Identity sourceIdentity) { + public Result handleProxyCall( + byte[] data, + UUID sourceUuid, + String sourceUsername, + Identity sourceIdentity + ) { if (sourceIdentity == Identity.SERVER) { // send it to the client return Result.forward(); } if (sourceIdentity == Identity.PLAYER) { - return handleServerCall(data, targetUuid, targetUsername); + return handleServerCall(data, sourceUuid, sourceUsername); } return Result.handled(); } @Override - public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) { + public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) { return Result.kick("Cannot send packets from Geyser/Floodgate to Floodgate"); } diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java index 2e82eceb..8b5b0a2d 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java @@ -51,16 +51,13 @@ public String getIdentifier() { @Override public Result handleProxyCall( byte[] data, - UUID targetUuid, - String targetUsername, - Identity targetIdentity, UUID sourceUuid, String sourceUsername, - Identity sourceIdentity) { - + Identity sourceIdentity + ) { // we can only get skins from Geyser (client) if (sourceIdentity == Identity.PLAYER) { - Result result = handleServerCall(data, targetUuid, targetUsername); + Result result = handleServerCall(data, sourceUuid, sourceUsername); // aka translate 'handled' into 'forward' when send-floodgate-data is enabled if (!result.isAllowed() && result.getReason() == null) { if (config.isProxy() && ((ProxyFloodgateConfig) config).isSendFloodgateData()) { @@ -78,8 +75,8 @@ public Result handleProxyCall( } @Override - public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) { - FloodgatePlayer floodgatePlayer = api.getPlayer(targetUuid); + public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) { + FloodgatePlayer floodgatePlayer = api.getPlayer(playerUuid); if (floodgatePlayer == null) { return Result.kick("Player sent skins data for a non-Floodgate player"); } diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/TransferChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/TransferChannel.java index 94e9982e..7ca754ed 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/TransferChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/TransferChannel.java @@ -42,27 +42,24 @@ public String getIdentifier() { @Override public Result handleProxyCall( byte[] data, - UUID targetUuid, - String targetUsername, - Identity targetIdentity, UUID sourceUuid, String sourceUsername, - Identity sourceIdentity) { - + Identity sourceIdentity + ) { if (sourceIdentity == Identity.SERVER) { // send it to the client return Result.forward(); } if (sourceIdentity == Identity.PLAYER) { - handleServerCall(data, targetUuid, targetUsername); + handleServerCall(data, sourceUuid, sourceUsername); } return Result.handled(); } @Override - public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) { + public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) { return Result.kick("I'm sorry, I'm unable to transfer a server :("); } diff --git a/velocity/src/main/java/org/geysermc/floodgate/pluginmessage/VelocityPluginMessageUtils.java b/velocity/src/main/java/org/geysermc/floodgate/pluginmessage/VelocityPluginMessageUtils.java index 482e5712..f6a8b75f 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/pluginmessage/VelocityPluginMessageUtils.java +++ b/velocity/src/main/java/org/geysermc/floodgate/pluginmessage/VelocityPluginMessageUtils.java @@ -33,7 +33,6 @@ import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; -import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSource; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import java.util.UUID; @@ -64,21 +63,6 @@ public void onPluginMessage(PluginMessageEvent event) { return; } - UUID targetUuid = null; - String targetUsername = null; - Identity targetIdentity = Identity.UNKNOWN; - - ChannelMessageSink target = event.getTarget(); - if (target instanceof Player) { - Player player = (Player) target; - targetUuid = player.getUniqueId(); - targetUsername = player.getUsername(); - targetIdentity = Identity.PLAYER; - - } else if (target instanceof ServerConnection) { - targetIdentity = Identity.SERVER; - } - UUID sourceUuid = null; String sourceUsername = null; Identity sourceIdentity = Identity.UNKNOWN; @@ -94,8 +78,9 @@ public void onPluginMessage(PluginMessageEvent event) { sourceIdentity = Identity.SERVER; } - Result result = channel.handleProxyCall(event.getData(), targetUuid, targetUsername, - targetIdentity, sourceUuid, sourceUsername, sourceIdentity); + Result result = channel.handleProxyCall( + event.getData(), sourceUuid, sourceUsername, sourceIdentity + ); event.setResult(result.isAllowed() ? ForwardResult.forward() : ForwardResult.handled()); From 0f152141a2788237d604920668bb7b6208898791 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 31 Aug 2022 03:03:42 +0200 Subject: [PATCH 036/113] Switched to Hikari for MySQL --- ...rLinkLoader.java => PlayerLinkHolder.java} | 82 ++- .../floodgate/module/CommonModule.java | 4 +- .../org/geysermc/floodgate/util/Metrics.java | 2 +- database/mysql/.editorconfig | 4 + database/mysql/build.gradle.kts | 6 +- .../floodgate/database/MysqlDatabase.java | 571 +++++++++--------- .../database/config/MysqlConfig.java | 8 +- settings.gradle.kts | 14 +- velocity/build.gradle.kts | 2 +- 9 files changed, 362 insertions(+), 331 deletions(-) rename core/src/main/java/org/geysermc/floodgate/link/{PlayerLinkLoader.java => PlayerLinkHolder.java} (74%) create mode 100644 database/mysql/.editorconfig diff --git a/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkLoader.java b/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java similarity index 74% rename from core/src/main/java/org/geysermc/floodgate/link/PlayerLinkLoader.java rename to core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java index b8febe29..618c9b27 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java @@ -32,6 +32,7 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; +import com.google.inject.name.Named; import com.google.inject.name.Names; import java.io.IOException; import java.io.InputStream; @@ -42,18 +43,23 @@ import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.inject.Named; +import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; +import org.geysermc.floodgate.config.FloodgateConfig.PlayerLinkConfig; +import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.InjectorHolder; import org.geysermc.floodgate.util.Utils; +@Listener @Singleton @SuppressWarnings("unchecked") -public final class PlayerLinkLoader { +public final class PlayerLinkHolder { @Inject private Injector injector; @Inject private FloodgateConfig config; @Inject private FloodgateLogger logger; @@ -62,30 +68,38 @@ public final class PlayerLinkLoader { @Named("dataDirectory") private Path dataDirectory; - @Nonnull + private URLClassLoader classLoader; + private PlayerLink instance; + + @NonNull public PlayerLink load() { + if (instance != null) { + return instance; + } + if (config == null) { throw new IllegalStateException("Config cannot be null!"); } - FloodgateConfig.PlayerLinkConfig lConfig = config.getPlayerLink(); - if (!lConfig.isEnabled()) { + PlayerLinkConfig linkConfig = config.getPlayerLink(); + if (!linkConfig.isEnabled()) { return new DisabledPlayerLink(); } List files; - try { - files = Files.list(dataDirectory) - .filter(path -> Files.isRegularFile(path) && path.toString().endsWith("jar")) + try (Stream list = Files.list(dataDirectory)) { + files = list + .filter(path -> Files.isRegularFile(path) && path.toString().endsWith(".jar")) .collect(Collectors.toList()); } catch (IOException exception) { logger.error("Failed to list possible database implementations", exception); return new DisabledPlayerLink(); } - // we can skip the rest if global linking is enabled and no database implementations has been - // found, or when global linking is enabled and own player linking is disabled. - if (lConfig.isEnableGlobalLinking() && (files.isEmpty() || !lConfig.isEnableOwnLinking())) { + // we can skip the rest if global linking is enabled and no database implementations has + // been found, or when global linking is enabled and own player linking is disabled. + if (linkConfig.isEnableGlobalLinking() && + (files.isEmpty() || !linkConfig.isEnableOwnLinking())) { return injector.getInstance(GlobalPlayerLinking.class); } @@ -100,7 +114,7 @@ public PlayerLink load() { // We only want to load one database implementation if (files.size() > 1) { boolean found = false; - databaseName = lConfig.getType(); + databaseName = linkConfig.getType(); String expectedName = "floodgate-" + databaseName + "-database.jar"; for (Path path : files) { @@ -111,14 +125,18 @@ public PlayerLink load() { } if (!found) { - logger.error("Failed to find an implementation for type: {}", lConfig.getType()); + logger.error( + "Failed to find an implementation for type: {}", linkConfig.getType() + ); return new DisabledPlayerLink(); } } else { String name = implementationPath.getFileName().toString(); if (!Utils.isValidDatabaseName(name)) { - logger.error("Found database {} but the name doesn't match {}", - name, Constants.DATABASE_NAME_FORMAT); + logger.error( + "Found database {} but the name doesn't match {}", + name, Constants.DATABASE_NAME_FORMAT + ); return new DisabledPlayerLink(); } int firstSplit = name.indexOf('-') + 1; @@ -133,24 +151,22 @@ public PlayerLink load() { // we don't have a way to close this properly since we have no stop method and we have // to be able to load classes on the fly, but that doesn't matter anyway since Floodgate // doesn't support reloading - URLClassLoader classLoader = new URLClassLoader( + classLoader = new URLClassLoader( new URL[]{pluginUrl}, - PlayerLinkLoader.class.getClassLoader() + PlayerLinkHolder.class.getClassLoader() ); String mainClassName; - JsonObject linkConfig; - - try (InputStream linkConfigStream = - classLoader.getResourceAsStream("init.json")) { + JsonObject dbInitConfig; + try (InputStream linkConfigStream = classLoader.getResourceAsStream("init.json")) { requireNonNull(linkConfigStream, "Implementation should have an init file"); - linkConfig = new Gson().fromJson( + dbInitConfig = new Gson().fromJson( new InputStreamReader(linkConfigStream), JsonObject.class ); - mainClassName = linkConfig.get("mainClass").getAsString(); + mainClassName = dbInitConfig.get("mainClass").getAsString(); } Class mainClass = @@ -167,16 +183,16 @@ public PlayerLink load() { Names.named("databaseClassLoader")).toInstance(classLoader); binder.bind(JsonObject.class) .annotatedWith(Names.named("databaseInitData")) - .toInstance(linkConfig); + .toInstance(dbInitConfig); binder.bind(InjectorHolder.class) .toInstance(injectorHolder); }); injectorHolder.set(linkInjector); - PlayerLink instance = linkInjector.getInstance(mainClass); + instance = linkInjector.getInstance(mainClass); // we use our own internal PlayerLinking when global linking is enabled - if (lConfig.isEnableGlobalLinking()) { + if (linkConfig.isEnableGlobalLinking()) { GlobalPlayerLinking linking = linkInjector.getInstance(GlobalPlayerLinking.class); linking.setDatabaseImpl(instance); linking.load(); @@ -186,8 +202,10 @@ public PlayerLink load() { return instance; } } catch (ClassCastException exception) { - logger.error("The database implementation ({}) doesn't extend the PlayerLink class!", - implementationPath.getFileName().toString(), exception); + logger.error( + "The database implementation ({}) doesn't extend the PlayerLink class!", + implementationPath.getFileName().toString(), exception + ); return new DisabledPlayerLink(); } catch (Exception exception) { if (init) { @@ -198,4 +216,10 @@ public PlayerLink load() { return new DisabledPlayerLink(); } } + + @Subscribe + public void onShutdown(ShutdownEvent ignored) throws Exception { + instance.stop(); + classLoader.close(); + } } diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 72cfd4bd..2ce7341b 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -55,7 +55,7 @@ import org.geysermc.floodgate.event.EventBus; import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher; import org.geysermc.floodgate.inject.CommonPlatformInjector; -import org.geysermc.floodgate.link.PlayerLinkLoader; +import org.geysermc.floodgate.link.PlayerLinkHolder; import org.geysermc.floodgate.packet.PacketHandlersImpl; import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; @@ -102,7 +102,7 @@ public FloodgateConfig floodgateConfig(ConfigLoader configLoader) { @Provides @Singleton - public PlayerLink playerLink(PlayerLinkLoader linkLoader) { + public PlayerLink playerLink(PlayerLinkHolder linkLoader) { return linkLoader.load(); } diff --git a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java index 474d6e7a..4ef585b7 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java @@ -26,13 +26,13 @@ package org.geysermc.floodgate.util; import com.google.inject.Inject; +import com.google.inject.name.Named; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.inject.Named; import org.bstats.MetricsBase; import org.bstats.charts.DrilldownPie; import org.bstats.charts.SimplePie; diff --git a/database/mysql/.editorconfig b/database/mysql/.editorconfig new file mode 100644 index 00000000..1f0feacf --- /dev/null +++ b/database/mysql/.editorconfig @@ -0,0 +1,4 @@ +[*] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 \ No newline at end of file diff --git a/database/mysql/build.gradle.kts b/database/mysql/build.gradle.kts index cc59658b..3b6f25a3 100644 --- a/database/mysql/build.gradle.kts +++ b/database/mysql/build.gradle.kts @@ -1,8 +1,10 @@ -val mariadbClientVersion = "2.7.4" +val mysqlClientVersion = "8.0.30" +val hikariVersion = "4.0.3" dependencies { provided(projects.core) - implementation("org.mariadb.jdbc", "mariadb-java-client" , mariadbClientVersion) + implementation("mysql", "mysql-connector-java", mysqlClientVersion) + implementation("com.zaxxer", "HikariCP", hikariVersion) } description = "The Floodgate database extension for MySQL" diff --git a/database/mysql/src/main/java/org/geysermc/floodgate/database/MysqlDatabase.java b/database/mysql/src/main/java/org/geysermc/floodgate/database/MysqlDatabase.java index 16797c6b..60c19716 100644 --- a/database/mysql/src/main/java/org/geysermc/floodgate/database/MysqlDatabase.java +++ b/database/mysql/src/main/java/org/geysermc/floodgate/database/MysqlDatabase.java @@ -25,6 +25,8 @@ package org.geysermc.floodgate.database; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.sql.Connection; @@ -43,309 +45,296 @@ import org.geysermc.floodgate.link.CommonPlayerLink; import org.geysermc.floodgate.link.LinkRequestImpl; import org.geysermc.floodgate.util.LinkedPlayer; -import org.mariadb.jdbc.MariaDbPoolDataSource; public class MysqlDatabase extends CommonPlayerLink { - private MariaDbPoolDataSource pool; - - @Override - public void load() { - getLogger().info("Connecting to a MySQL-like database..."); - try { - Class.forName("org.mariadb.jdbc.Driver"); - MysqlConfig databaseconfig = getConfig(MysqlConfig.class); - - pool = new MariaDbPoolDataSource(); - - String hostname = databaseconfig.getHostname(); - if (hostname.contains(":")) { - String[] split = hostname.split(":"); - - pool.setServerName(split[0]); - try { - pool.setPortNumber(Integer.parseInt(split[1])); - } catch (NumberFormatException exception) { - getLogger().info("{} is not a valid port! Will use the default port", split[1]); - } - } else { - pool.setServerName(hostname); - } - - pool.setUser(databaseconfig.getUsername()); - pool.setPassword(databaseconfig.getPassword()); - pool.setDatabaseName(databaseconfig.getDatabase()); - pool.setMinPoolSize(2); - pool.setMaxPoolSize(10); - - try (Connection connection = pool.getConnection()) { - try (Statement statement = connection.createStatement()) { - statement.executeUpdate( - "CREATE TABLE IF NOT EXISTS `LinkedPlayers` ( " + - "`bedrockId` BINARY(16) NOT NULL , " + - "`javaUniqueId` BINARY(16) NOT NULL , " + - "`javaUsername` VARCHAR(16) NOT NULL , " + - " PRIMARY KEY (`bedrockId`) , " + - " INDEX (`bedrockId`, `javaUniqueId`)" + - ") ENGINE = InnoDB;" - ); - statement.executeUpdate( - "CREATE TABLE IF NOT EXISTS `LinkedPlayersRequest` ( " + - "`javaUsername` VARCHAR(16) NOT NULL , `javaUniqueId` BINARY(16) NOT NULL , " + - "`linkCode` VARCHAR(16) NOT NULL , " + - "`bedrockUsername` VARCHAR(16) NOT NULL ," + - "`requestTime` BIGINT NOT NULL , " + - " PRIMARY KEY (`javaUsername`), INDEX(`requestTime`)" + - " ) ENGINE = InnoDB;" - ); - } - } - getLogger().info("Connected to MySQL-like database."); - } catch (ClassNotFoundException exception) { - getLogger().error("The required class to load the MySQL database wasn't found"); - } catch (SQLException exception) { - getLogger().error("Error while loading database", exception); + private HikariDataSource dataSource; + + @Override + public void load() { + getLogger().info("Connecting to a MySQL-like database..."); + try { + MysqlConfig config = getConfig(MysqlConfig.class); + + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver"); + hikariConfig.setJdbcUrl("jdbc:mysql://" + config.getHostname() + "/" + config.getDatabase()); + hikariConfig.setUsername(config.getUsername()); + hikariConfig.setPassword(config.getPassword()); + hikariConfig.setPoolName("floodgate-linking-mysql"); + hikariConfig.setMinimumIdle(5); + hikariConfig.setMaximumPoolSize(10); + + dataSource = new HikariDataSource(hikariConfig); + + try (Connection connection = dataSource.getConnection()) { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate( + "CREATE TABLE IF NOT EXISTS `LinkedPlayers` ( " + + "`bedrockId` BINARY(16) NOT NULL , " + + "`javaUniqueId` BINARY(16) NOT NULL , " + + "`javaUsername` VARCHAR(16) NOT NULL , " + + " PRIMARY KEY (`bedrockId`) , " + + " INDEX (`bedrockId`, `javaUniqueId`)" + + ") ENGINE = InnoDB;" + ); + statement.executeUpdate( + "CREATE TABLE IF NOT EXISTS `LinkedPlayersRequest` ( " + + "`javaUsername` VARCHAR(16) NOT NULL , `javaUniqueId` BINARY(16) NOT NULL , " + + "`linkCode` VARCHAR(16) NOT NULL , " + + "`bedrockUsername` VARCHAR(16) NOT NULL ," + + "`requestTime` BIGINT NOT NULL , " + + " PRIMARY KEY (`javaUsername`), INDEX(`requestTime`)" + + " ) ENGINE = InnoDB;" + ); } + } + getLogger().info("Connected to MySQL-like database."); + } catch (SQLException exception) { + getLogger().error("Error while loading database", exception); } - - @Override - public void stop() { - super.stop(); - pool.close(); - } - - @Override - @NonNull - public CompletableFuture getLinkedPlayer(@NonNull UUID bedrockId) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ?" - )) { - query.setBytes(1, uuidToBytes(bedrockId)); - try (ResultSet result = query.executeQuery()) { - if (!result.next()) { - return null; - } - String javaUsername = result.getString("javaUsername"); - UUID javaUniqueId = bytesToUUID(result.getBytes("javaUniqueId")); - return LinkedPlayer.of(javaUsername, javaUniqueId, bedrockId); - } - } - } catch (SQLException exception) { - getLogger().error("Error while getting LinkedPlayer", exception); - throw new CompletionException("Error while getting LinkedPlayer", exception); - } - }, getExecutorService()); - } - - @Override - @NonNull - public CompletableFuture isLinkedPlayer(@NonNull UUID playerId) { - return CompletableFuture.supplyAsync(() -> { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ? OR `javaUniqueId` = ?" - )) { - byte[] uuidBytes = uuidToBytes(playerId); - query.setBytes(1, uuidBytes); - query.setBytes(2, uuidBytes); - try (ResultSet result = query.executeQuery()) { - return result.next(); - } - } - } catch (SQLException exception) { - getLogger().error("Error while checking if player is a LinkedPlayer", exception); - throw new CompletionException( - "Error while checking if player is a LinkedPlayer", exception - ); + } + + @Override + public void stop() { + super.stop(); + dataSource.close(); + } + + @Override + @NonNull + public CompletableFuture getLinkedPlayer(@NonNull UUID bedrockId) { + return CompletableFuture.supplyAsync(() -> { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ?" + )) { + query.setBytes(1, uuidToBytes(bedrockId)); + try (ResultSet result = query.executeQuery()) { + if (!result.next()) { + return null; } - }, getExecutorService()); - } - - @Override - @NonNull - public CompletableFuture linkPlayer( - @NonNull UUID bedrockId, - @NonNull UUID javaId, - @NonNull String javaUsername) { - return CompletableFuture.runAsync( - () -> linkPlayer0(bedrockId, javaId, javaUsername), - getExecutorService()); - } - - private void linkPlayer0(UUID bedrockId, UUID javaId, String javaUsername) { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "INSERT INTO `LinkedPlayers` VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE " + - "`javaUniqueId`=VALUES(`javaUniqueId`), " + - "`javaUsername`=VALUES(`javaUsername`);" - )) { - query.setBytes(1, uuidToBytes(bedrockId)); - query.setBytes(2, uuidToBytes(javaId)); - query.setString(3, javaUsername); - query.executeUpdate(); - } - } catch (SQLException exception) { - getLogger().error("Error while linking player", exception); - throw new CompletionException("Error while linking player", exception); + String javaUsername = result.getString("javaUsername"); + UUID javaUniqueId = bytesToUUID(result.getBytes("javaUniqueId")); + return LinkedPlayer.of(javaUsername, javaUniqueId, bedrockId); + } } - } - - @Override - @NonNull - public CompletableFuture unlinkPlayer(@NonNull UUID javaId) { - return CompletableFuture.runAsync(() -> { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "DELETE FROM `LinkedPlayers` WHERE `javaUniqueId` = ? OR `bedrockId` = ?" - )) { - byte[] uuidBytes = uuidToBytes(javaId); - query.setBytes(1, uuidBytes); - query.setBytes(2, uuidBytes); - query.executeUpdate(); - } - } catch (SQLException exception) { - getLogger().error("Error while unlinking player", exception); - throw new CompletionException("Error while unlinking player", exception); - } - }, getExecutorService()); - } - - @Override - @NonNull - public CompletableFuture createLinkRequest( - @NonNull UUID javaId, - @NonNull String javaUsername, - @NonNull String bedrockUsername) { - return CompletableFuture.supplyAsync(() -> { - String linkCode = createCode(); - - createLinkRequest0(javaUsername, javaId, linkCode, bedrockUsername); - - return linkCode; - }, getExecutorService()); - } - - private void createLinkRequest0( - String javaUsername, - UUID javaId, - String linkCode, - String bedrockUsername) { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "INSERT INTO `LinkedPlayersRequest` VALUES (?, ?, ?, ?, ?) " + - "ON DUPLICATE KEY UPDATE " + - "`javaUniqueId`=VALUES(`javaUniqueId`), " + - "`linkCode`=VALUES(`linkCode`), " + - "`bedrockUsername`=VALUES(`bedrockUsername`), " + - "`requestTime`=VALUES(`requestTime`);" - )) { - query.setString(1, javaUsername); - query.setBytes(2, uuidToBytes(javaId)); - query.setString(3, linkCode); - query.setString(4, bedrockUsername); - query.setLong(5, Instant.now().getEpochSecond()); - query.executeUpdate(); - } - } catch (SQLException exception) { - getLogger().error("Error while linking player", exception); - throw new CompletionException("Error while linking player", exception); + } catch (SQLException exception) { + getLogger().error("Error while getting LinkedPlayer", exception); + throw new CompletionException("Error while getting LinkedPlayer", exception); + } + }, getExecutorService()); + } + + @Override + @NonNull + public CompletableFuture isLinkedPlayer(@NonNull UUID playerId) { + return CompletableFuture.supplyAsync(() -> { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ? OR `javaUniqueId` = ?" + )) { + byte[] uuidBytes = uuidToBytes(playerId); + query.setBytes(1, uuidBytes); + query.setBytes(2, uuidBytes); + try (ResultSet result = query.executeQuery()) { + return result.next(); + } } + } catch (SQLException exception) { + getLogger().error("Error while checking if player is a LinkedPlayer", exception); + throw new CompletionException( + "Error while checking if player is a LinkedPlayer", exception + ); + } + }, getExecutorService()); + } + + @Override + @NonNull + public CompletableFuture linkPlayer( + @NonNull UUID bedrockId, + @NonNull UUID javaId, + @NonNull String javaUsername) { + return CompletableFuture.runAsync( + () -> linkPlayer0(bedrockId, javaId, javaUsername), + getExecutorService()); + } + + private void linkPlayer0(UUID bedrockId, UUID javaId, String javaUsername) { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "INSERT INTO `LinkedPlayers` VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE " + + "`javaUniqueId`=VALUES(`javaUniqueId`), " + + "`javaUsername`=VALUES(`javaUsername`);" + )) { + query.setBytes(1, uuidToBytes(bedrockId)); + query.setBytes(2, uuidToBytes(javaId)); + query.setString(3, javaUsername); + query.executeUpdate(); + } + } catch (SQLException exception) { + getLogger().error("Error while linking player", exception); + throw new CompletionException("Error while linking player", exception); } - - private void removeLinkRequest(String javaUsername) { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "DELETE FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?" - )) { - query.setString(1, javaUsername); - query.executeUpdate(); - } - } catch (SQLException exception) { - getLogger().error("Error while cleaning up LinkRequest", exception); + } + + @Override + @NonNull + public CompletableFuture unlinkPlayer(@NonNull UUID javaId) { + return CompletableFuture.runAsync(() -> { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "DELETE FROM `LinkedPlayers` WHERE `javaUniqueId` = ? OR `bedrockId` = ?" + )) { + byte[] uuidBytes = uuidToBytes(javaId); + query.setBytes(1, uuidBytes); + query.setBytes(2, uuidBytes); + query.executeUpdate(); } + } catch (SQLException exception) { + getLogger().error("Error while unlinking player", exception); + throw new CompletionException("Error while unlinking player", exception); + } + }, getExecutorService()); + } + + @Override + @NonNull + public CompletableFuture createLinkRequest( + @NonNull UUID javaId, + @NonNull String javaUsername, + @NonNull String bedrockUsername + ) { + return CompletableFuture.supplyAsync(() -> { + String linkCode = createCode(); + + createLinkRequest0(javaUsername, javaId, linkCode, bedrockUsername); + + return linkCode; + }, getExecutorService()); + } + + private void createLinkRequest0( + String javaUsername, + UUID javaId, + String linkCode, + String bedrockUsername + ) { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "INSERT INTO `LinkedPlayersRequest` VALUES (?, ?, ?, ?, ?) " + + "ON DUPLICATE KEY UPDATE " + + "`javaUniqueId`=VALUES(`javaUniqueId`), " + + "`linkCode`=VALUES(`linkCode`), " + + "`bedrockUsername`=VALUES(`bedrockUsername`), " + + "`requestTime`=VALUES(`requestTime`);" + )) { + query.setString(1, javaUsername); + query.setBytes(2, uuidToBytes(javaId)); + query.setString(3, linkCode); + query.setString(4, bedrockUsername); + query.setLong(5, Instant.now().getEpochSecond()); + query.executeUpdate(); + } + } catch (SQLException exception) { + getLogger().error("Error while linking player", exception); + throw new CompletionException("Error while linking player", exception); } - - @Override - @NonNull - public CompletableFuture verifyLinkRequest( - @NonNull UUID bedrockId, - @NonNull String javaUsername, - @NonNull String bedrockUsername, - @NonNull String code) { - return CompletableFuture.supplyAsync(() -> { - LinkRequest request = getLinkRequest0(javaUsername); - - if (request == null || !isRequestedPlayer(request, bedrockId)) { - return LinkRequestResult.NO_LINK_REQUESTED; - } - - if (!request.getLinkCode().equals(code)) { - return LinkRequestResult.INVALID_CODE; - } - - // link request can be removed. Doesn't matter if the request is expired or not - removeLinkRequest(javaUsername); - - if (request.isExpired(getVerifyLinkTimeout())) { - return LinkRequestResult.REQUEST_EXPIRED; - } - - linkPlayer0(bedrockId, request.getJavaUniqueId(), javaUsername); - return LinkRequestResult.LINK_COMPLETED; - }, getExecutorService()); - } - - private LinkRequest getLinkRequest0(String javaUsername) { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "SELECT * FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?" - )) { - query.setString(1, javaUsername); - - try (ResultSet result = query.executeQuery()) { - if (result.next()) { - UUID javaId = bytesToUUID(result.getBytes(2)); - String linkCode = result.getString(3); - String bedrockUsername = result.getString(4); - long requestTime = result.getLong(5); - return new LinkRequestImpl(javaUsername, javaId, linkCode, bedrockUsername, - requestTime); - } - } - } - } catch (SQLException exception) { - getLogger().error("Error while getLinkRequest", exception); - throw new CompletionException("Error while getLinkRequest", exception); - } - return null; + } + + private void removeLinkRequest(String javaUsername) { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "DELETE FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?" + )) { + query.setString(1, javaUsername); + query.executeUpdate(); + } + } catch (SQLException exception) { + getLogger().error("Error while cleaning up LinkRequest", exception); } - - public void cleanLinkRequests() { - try (Connection connection = pool.getConnection()) { - try (PreparedStatement query = connection.prepareStatement( - "DELETE FROM `LinkedPlayersRequest` WHERE `requestTime` < ?" - )) { - query.setLong(1, Instant.now().getEpochSecond() - getVerifyLinkTimeout()); - query.executeUpdate(); - } - } catch (SQLException exception) { - getLogger().error("Error while cleaning up link requests", exception); + } + + @Override + @NonNull + public CompletableFuture verifyLinkRequest( + @NonNull UUID bedrockId, + @NonNull String javaUsername, + @NonNull String bedrockUsername, + @NonNull String code + ) { + return CompletableFuture.supplyAsync(() -> { + LinkRequest request = getLinkRequest0(javaUsername); + + if (request == null || !isRequestedPlayer(request, bedrockId)) { + return LinkRequestResult.NO_LINK_REQUESTED; + } + + if (!request.getLinkCode().equals(code)) { + return LinkRequestResult.INVALID_CODE; + } + + // link request can be removed. Doesn't matter if the request is expired or not + removeLinkRequest(javaUsername); + + if (request.isExpired(getVerifyLinkTimeout())) { + return LinkRequestResult.REQUEST_EXPIRED; + } + + linkPlayer0(bedrockId, request.getJavaUniqueId(), javaUsername); + return LinkRequestResult.LINK_COMPLETED; + }, getExecutorService()); + } + + private LinkRequest getLinkRequest0(String javaUsername) { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "SELECT * FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?" + )) { + query.setString(1, javaUsername); + + try (ResultSet result = query.executeQuery()) { + if (result.next()) { + UUID javaId = bytesToUUID(result.getBytes(2)); + String linkCode = result.getString(3); + String bedrockUsername = result.getString(4); + long requestTime = result.getLong(5); + return new LinkRequestImpl(javaUsername, javaId, linkCode, bedrockUsername, + requestTime); + } } + } + } catch (SQLException exception) { + getLogger().error("Error while getLinkRequest", exception); + throw new CompletionException("Error while getLinkRequest", exception); } - - private byte[] uuidToBytes(UUID uuid) { - byte[] uuidBytes = new byte[16]; - ByteBuffer.wrap(uuidBytes) - .order(ByteOrder.BIG_ENDIAN) - .putLong(uuid.getMostSignificantBits()) - .putLong(uuid.getLeastSignificantBits()); - return uuidBytes; - } - - private UUID bytesToUUID(byte[] uuidBytes) { - ByteBuffer buf = ByteBuffer.wrap(uuidBytes); - return new UUID(buf.getLong(), buf.getLong()); + return null; + } + + public void cleanLinkRequests() { + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement query = connection.prepareStatement( + "DELETE FROM `LinkedPlayersRequest` WHERE `requestTime` < ?" + )) { + query.setLong(1, Instant.now().getEpochSecond() - getVerifyLinkTimeout()); + query.executeUpdate(); + } + } catch (SQLException exception) { + getLogger().error("Error while cleaning up link requests", exception); } - + } + + private byte[] uuidToBytes(UUID uuid) { + byte[] uuidBytes = new byte[16]; + ByteBuffer.wrap(uuidBytes) + .order(ByteOrder.BIG_ENDIAN) + .putLong(uuid.getMostSignificantBits()) + .putLong(uuid.getLeastSignificantBits()); + return uuidBytes; + } + + private UUID bytesToUUID(byte[] uuidBytes) { + ByteBuffer buf = ByteBuffer.wrap(uuidBytes); + return new UUID(buf.getLong(), buf.getLong()); + } } diff --git a/database/mysql/src/main/java/org/geysermc/floodgate/database/config/MysqlConfig.java b/database/mysql/src/main/java/org/geysermc/floodgate/database/config/MysqlConfig.java index 0a2e0c26..b85748e7 100644 --- a/database/mysql/src/main/java/org/geysermc/floodgate/database/config/MysqlConfig.java +++ b/database/mysql/src/main/java/org/geysermc/floodgate/database/config/MysqlConfig.java @@ -29,8 +29,8 @@ @Getter public class MysqlConfig implements DatabaseConfig { - private String hostname = "localhost"; - private String database = "floodgate"; - private String username = "floodgate"; - private String password; + private String hostname = "localhost"; + private String database = "floodgate"; + private String username = "floodgate"; + private String password; } diff --git a/settings.gradle.kts b/settings.gradle.kts index 4a44a9d9..bcd33b65 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,7 +14,19 @@ dependencyResolutionManagement { } // Paper, Velocity - maven("https://papermc.io/repo/repository/maven-public") +// maven("https://repo.papermc.io/repository/maven-releases") { +// mavenContent { releasesOnly() } +// } +// maven("https://repo.papermc.io/repository/maven-snapshots") { +// mavenContent { snapshotsOnly() } +// } + maven("https://repo.papermc.io/repository/maven-public") { + content { + includeGroupByRegex( + "(io\\.papermc\\..*|com\\.destroystokyo\\..*|com\\.velocitypowered)" + ) + } + } // Spigot maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") { mavenContent { snapshotsOnly() } diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 2ddcfae5..5cd7064a 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -1,4 +1,4 @@ -var velocityVersion = "3.0.1" +var velocityVersion = "3.1.1" var log4jVersion = "2.11.2" var gsonVersion = "2.8.8" var guavaVersion = "25.1-jre" From 359484b3bec2770961719cbd8cf26a879f284d86 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 31 Aug 2022 10:32:20 -0700 Subject: [PATCH 037/113] SkinApplier now only applies a skin if a player doesn't already have one (#330) * SkinApplier now only applies a skin if a player doesn't already have one * add `hasSkin` method to SkinApplier and check for exising skins before overwriting * remove the use of Streams and Optionals * correct delay in SpigotSkinApplier to use ticks instead of milliseconds * Minor changes Co-authored-by: Tim203 --- .../floodgate/listener/BungeeListener.java | 2 +- .../pluginmessage/BungeeSkinApplier.java | 44 ++++++++++++++++--- .../pluginmessage/channel/SkinChannel.java | 2 +- .../geysermc/floodgate/skin/SkinApplier.java | 15 +++++++ .../floodgate/skin/SkinUploadSocket.java | 2 +- .../pluginmessage/SpigotSkinApplier.java | 27 +++++++++++- .../floodgate/util/VelocitySkinApplier.java | 18 ++++++++ 7 files changed, 100 insertions(+), 10 deletions(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java index e62a1776..5aa717f8 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java +++ b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java @@ -130,7 +130,7 @@ public void onPostLogin(PostLoginEvent event) { // To fix the February 2 2022 Mojang authentication changes if (!config.isSendFloodgateData()) { FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); - if (player != null && !player.isLinked()) { + if (player != null && !player.isLinked() && !skinApplier.hasSkin(player)) { skinApplier.applySkin(player, new SkinData("", "")); } } diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index 5c0dce97..3e360615 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -39,6 +39,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.connection.LoginResult; +import net.md_5.bungee.protocol.Property; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.skin.SkinApplier; @@ -85,11 +86,8 @@ public void applySkin(FloodgatePlayer uuid, SkinData skinData) { return; } - InitialHandler handler; - try { - handler = (InitialHandler) player.getPendingConnection(); - } catch (Exception exception) { - logger.error("Incompatible Bungeecord fork detected", exception); + InitialHandler handler = getHandler(player); + if (handler == null) { return; } @@ -114,4 +112,40 @@ public void applySkin(FloodgatePlayer uuid, SkinData skinData) { ReflectionUtils.invoke(loginResult, SET_PROPERTIES_METHOD, propertyArray); } + + @Override + public boolean hasSkin(FloodgatePlayer fPlayer) { + ProxiedPlayer player = ProxyServer.getInstance().getPlayer(fPlayer.getCorrectUniqueId()); + if (player == null) { + return false; + } + + InitialHandler handler = getHandler(player); + if (handler == null) { + return false; + } + + LoginResult loginResult = handler.getLoginProfile(); + if (loginResult == null) { + return false; + } + + for (Property property : loginResult.getProperties()) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return true; + } + } + } + return false; + } + + private InitialHandler getHandler(ProxiedPlayer player) { + try { + return (InitialHandler) player.getPendingConnection(); + } catch (Exception exception) { + logger.error("Incompatible Bungeecord fork detected", exception); + return null; + } + } } diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java index 8b5b0a2d..02f0161b 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java @@ -89,7 +89,7 @@ public Result handleServerCall(byte[] data, UUID playerUuid, String playerUserna return Result.kick("Got invalid skin data"); } - if (floodgatePlayer.isLinked()) { + if (floodgatePlayer.isLinked() || skinApplier.hasSkin(floodgatePlayer)) { return Result.handled(); } diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java index 0386b723..93dc3cb4 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java @@ -28,5 +28,20 @@ import org.geysermc.floodgate.api.player.FloodgatePlayer; public interface SkinApplier { + /** + * Apply a skin to a {@link FloodgatePlayer player} + * + * @param floodgatePlayer player to apply skin to + * @param skinData data for skin to apply to player + */ void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData); + + /** + * Check if a {@link FloodgatePlayer player} currently + * has a skin applied. + * + * @param floodgatePlayer player to check skin of + * @return if player has a skin + */ + boolean hasSkin(FloodgatePlayer floodgatePlayer); } diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java index 87c04459..c933d7f0 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java @@ -114,7 +114,7 @@ public void onMessage(String data) { player.getCorrectUsername()); return; } - if (!player.isLinked()) { + if (!player.isLinked() && !applier.hasSkin(player)) { SkinData skinData = SkinData.from(message.getAsJsonObject("data")); player.addProperty(PropertyKey.SKIN_UPLOADED, skinData); applier.applySkin(player, skinData); diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index 86f64c96..7ac668fe 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -25,6 +25,7 @@ package org.geysermc.floodgate.pluginmessage; +import com.destroystokyo.paper.profile.ProfileProperty; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -54,6 +55,24 @@ public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) { applySkin0(floodgatePlayer, skinData, true); } + @Override + public boolean hasSkin(FloodgatePlayer floodgatePlayer) { + Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId()); + + if (player == null) { + return false; + } + + for (ProfileProperty property : player.getPlayerProfile().getProperties()) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return true; + } + } + } + return false; + } + private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, boolean firstTry) { Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId()); @@ -61,8 +80,12 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool if (player == null) { if (firstTry) { Bukkit.getScheduler().runTaskLater(plugin, - () -> applySkin0(floodgatePlayer, skinData, false), - 10 * 1000); + () -> { + if (hasSkin(floodgatePlayer)) { + applySkin0(floodgatePlayer, skinData, false); + } + }, + 10 * 20); } return; } diff --git a/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java b/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java index 2d925725..c2c66d2f 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java +++ b/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java @@ -25,10 +25,12 @@ package org.geysermc.floodgate.util; +import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.util.GameProfile.Property; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.skin.SkinApplier; @@ -46,4 +48,20 @@ public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) { player.setGameProfileProperties(properties); }); } + + @Override + public boolean hasSkin(FloodgatePlayer floodgatePlayer) { + Optional player = server.getPlayer(floodgatePlayer.getCorrectUniqueId()); + + if (player.isPresent()) { + for (Property property : player.get().getGameProfileProperties()) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return true; + } + } + } + } + return false; + } } From 1a6aa3199db2a94070d9f80b0b1ba98b52e8dfb9 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 31 Aug 2022 20:53:38 +0200 Subject: [PATCH 038/113] Updated to the latest events version. Share a thread pool --- .../geysermc/floodgate/event/EventBus.java | 19 ++++++++++++------- .../floodgate/event/EventSubscriber.java | 12 +++++++++--- .../floodgate/link/CommonPlayerLink.java | 2 +- .../floodgate/module/CommonModule.java | 9 +++++++++ .../geysermc/floodgate/news/NewsChecker.java | 18 +++--------------- .../geysermc/floodgate/util/HttpClient.java | 18 +++++++----------- 6 files changed, 41 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/event/EventBus.java b/core/src/main/java/org/geysermc/floodgate/event/EventBus.java index be768c51..abef2db2 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/EventBus.java +++ b/core/src/main/java/org/geysermc/floodgate/event/EventBus.java @@ -27,6 +27,8 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.PostOrder; import org.geysermc.event.bus.impl.EventBusImpl; import org.geysermc.event.subscribe.Subscribe; import org.geysermc.event.subscribe.Subscriber; @@ -35,10 +37,11 @@ public final class EventBus extends EventBusImpl> { @Override protected > B makeSubscription( - Class eventClass, - Subscribe subscribe, - H listener, - BiConsumer handler) { + @NonNull Class eventClass, + @NonNull Subscribe subscribe, + @NonNull H listener, + @NonNull BiConsumer handler + ) { return (B) new EventSubscriber<>( eventClass, subscribe.postOrder(), subscribe.ignoreCancelled(), listener, handler ); @@ -46,8 +49,10 @@ protected > B makeSubscription( @Override protected > B makeSubscription( - Class eventClass, - Consumer handler) { - return (B) new EventSubscriber<>(eventClass, handler); + @NonNull Class eventClass, + @NonNull Consumer handler, + @NonNull PostOrder postOrder + ) { + return (B) new EventSubscriber<>(eventClass, handler, postOrder); } } diff --git a/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java b/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java index 1ac57cf7..e37d2fa1 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java +++ b/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java @@ -27,12 +27,17 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.PostOrder; import org.geysermc.event.subscribe.impl.SubscriberImpl; public final class EventSubscriber extends SubscriberImpl { - EventSubscriber(Class eventClass, Consumer handler) { - super(eventClass, handler); + EventSubscriber( + @NonNull Class eventClass, + @NonNull Consumer handler, + @NonNull PostOrder postOrder + ) { + super(eventClass, handler, postOrder); } EventSubscriber( @@ -40,7 +45,8 @@ EventSubscriber( PostOrder postOrder, boolean ignoreCancelled, H handlerInstance, - BiConsumer handler) { + BiConsumer handler + ) { super(eventClass, postOrder, ignoreCancelled, handlerInstance, handler); } } diff --git a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java index c683c3e3..f1bfb912 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java +++ b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java @@ -49,7 +49,7 @@ @Listener public abstract class CommonPlayerLink implements PlayerLink { @Getter(AccessLevel.PROTECTED) - private final ExecutorService executorService = Executors.newFixedThreadPool(11); + private final ExecutorService executorService = Executors.newCachedThreadPool(); @Getter private boolean enabled; @Getter private boolean allowLinking; diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 2ce7341b..050c4925 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -30,12 +30,16 @@ import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; +import com.google.inject.name.Names; import com.google.inject.spi.InjectionListener; import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; import io.netty.util.AttributeKey; import java.nio.file.Path; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import lombok.RequiredArgsConstructor; +import org.geysermc.event.PostOrder; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi; @@ -53,6 +57,7 @@ import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; import org.geysermc.floodgate.event.EventBus; +import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher; import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.link.PlayerLinkHolder; @@ -80,6 +85,10 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { } }); + ExecutorService commonPool = Executors.newCachedThreadPool(); + eventBus.subscribe(ShutdownEvent.class, ignored -> commonPool.shutdown(), PostOrder.LAST); + bind(ExecutorService.class).annotatedWith(Names.named("commonPool")).toInstance(commonPool); + bind(HttpClient.class).in(Singleton.class); bind(FloodgateApi.class).to(SimpleFloodgateApi.class); diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index 8071a94d..a653ca59 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -34,14 +34,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.geysermc.event.Listener; -import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.command.util.Permission; -import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.news.data.AnnouncementData; import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.CheckAfterData; @@ -52,10 +48,11 @@ import org.geysermc.floodgate.util.HttpClient.HttpResponse; @AutoBind -@Listener public class NewsChecker { - private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); private final Map activeNewsItems = new HashMap<>(); + @Inject + @Named("commonPool") + private ScheduledExecutorService executorService; @Inject private CommandUtil commandUtil; @@ -204,13 +201,4 @@ private void activateNews(NewsItem item) { handleNewsItem(null, item, action); } } - - public void shutdown() { - executorService.shutdown(); - } - - @Subscribe - public void onShutdown(ShutdownEvent ignored) { - shutdown(); - } } diff --git a/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java index e665025f..96568fec 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java +++ b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java @@ -27,30 +27,31 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.event.Listener; -import org.geysermc.event.subscribe.Subscribe; -import org.geysermc.floodgate.event.ShutdownEvent; // resources are properly closed and ignoring the original stack trace is intended @SuppressWarnings({"PMD.CloseResource", "PMD.PreserveStackTrace"}) -@Listener +@Singleton public class HttpClient { private static final String USER_AGENT = "GeyserMC/Floodgate"; - private final ExecutorService executorService = Executors.newSingleThreadExecutor(); private final Gson gson = new Gson(); + @Inject + @Named("commonPool") + private ExecutorService executorService; public CompletableFuture asyncGet(String urlString) { return CompletableFuture.supplyAsync(() -> get(urlString), executorService); @@ -162,11 +163,6 @@ private InputStreamReader createReader(HttpURLConnection connection) { return null; } - @Subscribe - public void onShutdown(ShutdownEvent ignored) { - executorService.shutdown(); - } - @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public static class HttpResponse { From bc1a98c31aa2c74c6a12acba471400db65cf8479 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 2 Sep 2022 09:54:38 +0200 Subject: [PATCH 039/113] News needs a scheduled executor --- .../geysermc/floodgate/news/NewsChecker.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index a653ca59..cdbeed07 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -34,10 +34,14 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.command.util.Permission; +import org.geysermc.floodgate.event.ShutdownEvent; import org.geysermc.floodgate.news.data.AnnouncementData; import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.CheckAfterData; @@ -48,11 +52,10 @@ import org.geysermc.floodgate.util.HttpClient.HttpResponse; @AutoBind +@Listener public class NewsChecker { + private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); private final Map activeNewsItems = new HashMap<>(); - @Inject - @Named("commonPool") - private ScheduledExecutorService executorService; @Inject private CommandUtil commandUtil; @@ -196,6 +199,15 @@ public void addNews(NewsItem item) { activateNews(item); } + public void shutdown() { + executorService.shutdown(); + } + + @Subscribe + public void onShutdown(ShutdownEvent ignored) { + shutdown(); + } + private void activateNews(NewsItem item) { for (NewsItemAction action : item.getActions()) { handleNewsItem(null, item, action); From 49cf3a0a949ee5e2becfb57a31ea6fa313f1b98b Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 16 Oct 2022 17:47:05 +0200 Subject: [PATCH 040/113] Bumped version to 2.1.1 and publish entire java component --- .../src/main/kotlin/floodgate.publish-conventions.gradle.kts | 3 +-- build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts index 60c3e272..ad119489 100644 --- a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts @@ -11,8 +11,7 @@ publishing { artifactId = project.name version = project.version as String - artifact(tasks["shadowJar"]) - artifact(tasks["sourcesJar"]) + from(components["java"]) } } } diff --git a/build.gradle.kts b/build.gradle.kts index b64f35aa..9eac848e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { allprojects { group = "org.geysermc.floodgate" - version = "2.2.0-SNAPSHOT" + version = "2.2.1-SNAPSHOT" description = "Allows Bedrock players to join Java edition servers while keeping the server in online mode" } From 90e9b1e3fcbff8679c0ed4d10cc9aeeea0e640dd Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 27 Oct 2022 15:10:22 -0400 Subject: [PATCH 041/113] Fix checking for existing skins on Spigot (#362) --- .../pluginmessage/SpigotSkinApplier.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index 7ac668fe..da210f77 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -25,7 +25,6 @@ package org.geysermc.floodgate.pluginmessage; -import com.destroystokyo.paper.profile.ProfileProperty; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -63,11 +62,16 @@ public boolean hasSkin(FloodgatePlayer floodgatePlayer) { return false; } - for (ProfileProperty property : player.getPlayerProfile().getProperties()) { - if (property.getName().equals("textures")) { - if (!property.getValue().isEmpty()) { - return true; - } + GameProfile profile = ReflectionUtils.castedInvoke(player, ClassNames.GET_PROFILE_METHOD); + if (profile == null) { + throw new IllegalStateException("The GameProfile cannot be null! " + player.getName()); + } + + // Need to be careful here - getProperties() returns an authlib PropertyMap, which extends + // MultiMap from Guava. Floodgate relocates Guava. + for (Property textures : profile.getProperties().get("textures")) { + if (!textures.getValue().isEmpty()) { + return true; } } return false; From c2b887f5a7b0425ffa4cbee20cd08069fd7c68e6 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 27 Oct 2022 15:12:07 -0400 Subject: [PATCH 042/113] Close all skin sockets on shutdown (#363) --- .../geysermc/floodgate/module/CommonModule.java | 4 +++- .../floodgate/skin/SkinUploadManager.java | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 050c4925..c597922c 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -170,7 +170,9 @@ public SkinUploadManager skinUploadManager( FloodgateApi api, SkinApplier skinApplier, FloodgateLogger logger) { - return new SkinUploadManager(api, skinApplier, logger); + SkinUploadManager manager = new SkinUploadManager(api, skinApplier, logger); + eventBus.register(manager); + return manager; } @Provides diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java index a6c49395..1603723d 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java @@ -29,9 +29,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import lombok.AllArgsConstructor; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.event.ShutdownEvent; +@Listener @AllArgsConstructor public final class SkinUploadManager { private final Int2ObjectMap connections = @@ -53,4 +57,16 @@ public void addConnectionIfNeeded(int id, String verifyCode) { public void removeConnection(int id, SkinUploadSocket socket) { connections.remove(id, socket); } + + public void closeAllSockets() { + for (SkinUploadSocket socket : connections.values()) { + socket.close(); + } + connections.clear(); + } + + @Subscribe + public void onShutdown(ShutdownEvent ignored) { + closeAllSockets(); + } } From c2a1932080747587cd93a33153b8578c6812f6f1 Mon Sep 17 00:00:00 2001 From: mastermc05 <63639746+mastermc05@users.noreply.github.com> Date: Sat, 29 Oct 2022 13:31:17 +0300 Subject: [PATCH 043/113] Only apply skin when someone doesn't have a skin applied already (#365) Instead of aplying only when the player has a skin apply only when it doesn't have a skin --- .../org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index da210f77..edc57279 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -85,7 +85,7 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool if (firstTry) { Bukkit.getScheduler().runTaskLater(plugin, () -> { - if (hasSkin(floodgatePlayer)) { + if (!hasSkin(floodgatePlayer)) { applySkin0(floodgatePlayer, skinData, false); } }, From dafb5e4b587a0b955385d484f321e9c68dc101b3 Mon Sep 17 00:00:00 2001 From: mastermc05 <63639746+mastermc05@users.noreply.github.com> Date: Fri, 4 Nov 2022 12:36:28 +0200 Subject: [PATCH 044/113] Use UTF-8 for language files (#366) Languages like ru_RU don't work because they have specific characters, and your files are encoded in UTF-8, but it reads them as ISO 8859-1 --- core/src/main/java/org/geysermc/floodgate/util/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/floodgate/util/Utils.java b/core/src/main/java/org/geysermc/floodgate/util/Utils.java index c1765cbf..d182f580 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Utils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Utils.java @@ -75,7 +75,7 @@ public static Properties readProperties(String resourceFile) { if (is == null) { return null; } - properties.load(is); + properties.load(new InputStreamReader(is, StandardCharsets.UTF_8)); } catch (IOException e) { throw new AssertionError("Failed to read properties file", e); } From d3705bfd317905fdb1ceb05f0986f1ed2a2adddf Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 8 Nov 2022 19:30:39 +0100 Subject: [PATCH 045/113] Fixed building Floodgate and added a version subcommand --- .../floodgate/command/main/MainCommand.java | 1 + .../command/main/VersionSubcommand.java | 129 ++++++++++++++++++ .../floodgate/command/util/Permission.java | 1 + .../geysermc/floodgate/util/HttpClient.java | 16 ++- .../org/geysermc/floodgate/util/Utils.java | 1 + 5 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java index a2de48fa..446e8106 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java @@ -42,6 +42,7 @@ public final class MainCommand extends SubCommands implements FloodgateCommand { public MainCommand() { defineSubCommand(FirewallCheckSubcommand.class); + defineSubCommand(VersionSubcommand.class); } @Override diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java new file mode 100644 index 00000000..ea985778 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.command.main; + +import static org.geysermc.floodgate.util.Constants.COLOR_CHAR; + +import cloud.commandframework.context.CommandContext; +import com.google.gson.JsonElement; +import com.google.inject.Inject; +import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.command.WhitelistCommand.Message; +import org.geysermc.floodgate.command.util.Permission; +import org.geysermc.floodgate.platform.command.FloodgateSubCommand; +import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.util.Constants; +import org.geysermc.floodgate.util.HttpClient; + +public class VersionSubcommand extends FloodgateSubCommand { + @Inject + private HttpClient httpClient; + + @Inject + private FloodgateLogger logger; + + @Override + public String name() { + return "version"; + } + + @Override + public String description() { + return "Displays version information about Floodgate"; + } + + @Override + public Permission permission() { + return Permission.COMMAND_MAIN_VERSION; + } + + @Override + public void execute(CommandContext context) { + UserAudience sender = context.getSender(); + sender.sendMessage(String.format( + COLOR_CHAR + "7You're currently on " + COLOR_CHAR + "b%s" + + COLOR_CHAR + "7 (branch: " + COLOR_CHAR + "b%s" + COLOR_CHAR + "7)\n" + + COLOR_CHAR + "eFetching latest build info...", + Constants.VERSION, Constants.GIT_BRANCH + )); + + String baseUrl = String.format( + "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/", + Constants.GIT_BRANCH + ); + + httpClient.asyncGet( + baseUrl + "buildNumber", + JsonElement.class + ).whenComplete((result, error) -> { + if (error != null) { + sender.sendMessage(COLOR_CHAR + "cCould not retrieve latest version info!"); + error.printStackTrace(); + return; + } + + JsonElement response = result.getResponse(); + + logger.info(String.valueOf(response)); + logger.info("{}", result.getHttpCode()); + + if (result.getHttpCode() == 404) { + sender.sendMessage( + COLOR_CHAR + "cGot a 404 (not found) while requesting the latest version." + + " Are you using a custom Floodgate version?" + ); + return; + } + + if (!result.isCodeOk()) { + //todo make it more generic instead of using a Whitelist command strings + logger.error( + "Got an error from requesting the latest Floodgate version: {}", + response.toString() + ); + sender.sendMessage(Message.UNEXPECTED_ERROR); + return; + } + + int buildNumber = response.getAsInt(); + + if (buildNumber > Constants.BUILD_NUMBER) { + sender.sendMessage(String.format( + COLOR_CHAR + "7There is a newer version of Floodgate available!\n" + + COLOR_CHAR + "7You are " + COLOR_CHAR + "e%s " + COLOR_CHAR + "7builds behind.\n" + + COLOR_CHAR + "7Download the latest Floodgate version here: " + COLOR_CHAR + "b%s", + buildNumber - Constants.BUILD_NUMBER, baseUrl + )); + return; + } + if (buildNumber == Constants.BUILD_NUMBER) { + sender.sendMessage(COLOR_CHAR + "aYou're running the latest version of Floodgate!"); + return; + } + sender.sendMessage(COLOR_CHAR + "cCannot check version for custom Floodgate versions!"); + }); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/command/util/Permission.java b/core/src/main/java/org/geysermc/floodgate/command/util/Permission.java index 90f897fb..87c2ec52 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/util/Permission.java +++ b/core/src/main/java/org/geysermc/floodgate/command/util/Permission.java @@ -31,6 +31,7 @@ public enum Permission { COMMAND_MAIN("floodgate.command.floodgate", TRUE), COMMAND_MAIN_FIREWALL(COMMAND_MAIN, "firewall", OP), + COMMAND_MAIN_VERSION(COMMAND_MAIN, "version", OP), COMMAND_LINK("floodgate.command.linkaccount", TRUE), COMMAND_UNLINK("floodgate.command.unlinkaccount", TRUE), COMMAND_WHITELIST("floodgate.command.fwhitelist", OP), diff --git a/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java index 96568fec..960dc1b1 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java +++ b/core/src/main/java/org/geysermc/floodgate/util/HttpClient.java @@ -57,6 +57,10 @@ public CompletableFuture asyncGet(String urlString) { return CompletableFuture.supplyAsync(() -> get(urlString), executorService); } + public CompletableFuture> asyncGet(String urlString, Class response) { + return CompletableFuture.supplyAsync(() -> get(urlString, response), executorService); + } + public DefaultHttpResponse get(String urlString) { return readDefaultResponse(request(urlString)); } @@ -99,12 +103,14 @@ private HttpResponse readResponse(HttpURLConnection connection, Class return new HttpResponse<>(-1, null); } + int responseCode = -1; try { - int responseCode = connection.getResponseCode(); + responseCode = connection.getResponseCode(); T response = gson.fromJson(streamReader, clazz); return new HttpResponse<>(responseCode, response); } catch (Exception ignored) { - return new HttpResponse<>(-1, null); + // e.g. when the response isn't JSON + return new HttpResponse<>(responseCode, null); } finally { try { streamReader.close(); @@ -149,11 +155,7 @@ private InputStreamReader createReader(HttpURLConnection connection) { try { stream = connection.getInputStream(); } catch (Exception exception) { - try { - stream = connection.getErrorStream(); - } catch (Exception exception1) { - throw new RuntimeException("Both the input and the error stream failed?!"); - } + stream = connection.getErrorStream(); } // it's null for example when it couldn't connect to the server diff --git a/core/src/main/java/org/geysermc/floodgate/util/Utils.java b/core/src/main/java/org/geysermc/floodgate/util/Utils.java index d182f580..19ef78de 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Utils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Utils.java @@ -35,6 +35,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.annotation.Annotation; +import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.Properties; import java.util.Set; From 2c92e3e215e67ab20a5f7417504f520735a0c700 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 11 Dec 2022 21:34:47 +0100 Subject: [PATCH 046/113] Remove Blossom and use templates --- build-logic/build.gradle.kts | 1 + .../floodgate.generate-templates.gradle.kts | 93 +++++++++++++++++++ core/build.gradle.kts | 15 ++- .../geysermc/floodgate/util/Constants.java | 10 +- settings.gradle.kts | 3 - 5 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 build-logic/src/main/kotlin/floodgate.generate-templates.gradle.kts rename core/src/main/{java => templates}/org/geysermc/floodgate/util/Constants.java (92%) diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 64ac14db..75f6eda2 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { implementation("net.kyori", "indra-common", "2.0.6") implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1") implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1") + implementation("gradle.plugin.org.jetbrains.gradle.plugin.idea-ext", "gradle-idea-ext", "1.1.7") } tasks.withType { diff --git a/build-logic/src/main/kotlin/floodgate.generate-templates.gradle.kts b/build-logic/src/main/kotlin/floodgate.generate-templates.gradle.kts new file mode 100644 index 00000000..5f89b302 --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate.generate-templates.gradle.kts @@ -0,0 +1,93 @@ +import org.apache.tools.ant.filters.ReplaceTokens +import org.gradle.plugins.ide.eclipse.model.EclipseModel +import org.gradle.plugins.ide.idea.model.IdeaModel +import org.jetbrains.gradle.ext.ProjectSettings +import org.jetbrains.gradle.ext.TaskTriggersConfig + +plugins { + id("org.jetbrains.gradle.plugin.idea-ext") +} + +registerGenerateTemplateTasks() + +fun Project.registerGenerateTemplateTasks() { + // main and test + extensions.getByType().all { + val javaDestination = layout.buildDirectory.dir("generated/sources/templates/$name") + val javaSrcDir = layout.projectDirectory.dir("src/$name/templates") + val javaGenerateTask = tasks.register( + getTaskName("template", "sources") + ) { + filteringCharset = Charsets.UTF_8.name() + from(javaSrcDir) + into(javaDestination) + filter("tokens" to replacements()) + } + java.srcDir(javaGenerateTask.map { it.outputs }) + + val resourcesDestination = layout.buildDirectory.dir("generated/resources/templates/$name") + val resourcesSrcDir = layout.projectDirectory.dir("src/$name/resourceTemplates") + val resourcesGenerateTask = tasks.register( + getTaskName("template", "resources") + ) { + filteringCharset = Charsets.UTF_8.name() + from(resourcesSrcDir) + into(resourcesDestination) + filter("tokens" to replacements()) + } + resources.srcDir(resourcesGenerateTask.map { it.outputs }) + } + + return configureIdeSync( + tasks.register("allTemplateSources") { + dependsOn(tasks.withType()) + }, + tasks.register("allTemplateResources") { + dependsOn(tasks.withType()) + } + ) +} + +fun Project.configureIdeSync(vararg generateAllTasks: TaskProvider) { + extensions.findByType { + synchronizationTasks(generateAllTasks) + } + + extensions.findByType { + if (project != null) { + (project as ExtensionAware).extensions.configure { + (this as ExtensionAware).extensions.configure { + afterSync(generateAllTasks) + } + } + } + } + + //todo wasn't able to find something for VS(Code) +} + +inline fun ExtensionContainer.findByType(noinline action: T.() -> Unit) { + val extension = findByType(T::class) + if (extension != null) { + action.invoke(extension) + } +} + +abstract class GenerateAnyTemplates : Copy() { + private val replacements = mutableMapOf() + + fun replaceToken(key: String, value: () -> Any) { + replaceToken(key, value.invoke()) + } + + fun replaceToken(key: String, value: Any) { + replacements[key] = value.toString() + } + + fun replacements(): Map { + return replacements + } +} + +open class GenerateResourceTemplates : GenerateAnyTemplates() +open class GenerateSourceTemplates : GenerateAnyTemplates() diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 6a4eb0bc..d7d48737 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,7 +1,5 @@ -import net.kyori.blossom.BlossomExtension - plugins { - id("net.kyori.blossom") + id("floodgate.generate-templates") } dependencies { @@ -26,9 +24,10 @@ provided("io.netty", "netty-codec", Versions.nettyVersion) relocate("org.bstats") -configure { - val constantsFile = "src/main/java/org/geysermc/floodgate/util/Constants.java" - replaceToken("\${floodgateVersion}", fullVersion(), constantsFile) - replaceToken("\${branch}", branchName(), constantsFile) - replaceToken("\${buildNumber}", buildNumber(), constantsFile) +tasks { + templateSources { + replaceToken("floodgateVersion", fullVersion()) + replaceToken("branch", branchName()) + replaceToken("buildNumber", buildNumber()) + } } diff --git a/core/src/main/java/org/geysermc/floodgate/util/Constants.java b/core/src/main/templates/org/geysermc/floodgate/util/Constants.java similarity index 92% rename from core/src/main/java/org/geysermc/floodgate/util/Constants.java rename to core/src/main/templates/org/geysermc/floodgate/util/Constants.java index 5e97aba3..b79a610f 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Constants.java +++ b/core/src/main/templates/org/geysermc/floodgate/util/Constants.java @@ -26,12 +26,12 @@ package org.geysermc.floodgate.util; public final class Constants { - public static final String VERSION = "${floodgateVersion}"; - public static final int BUILD_NUMBER = Integer.parseInt("${buildNumber}"); - public static final String GIT_BRANCH = "${branch}"; + public static final String VERSION = "@floodgateVersion@"; + public static final int BUILD_NUMBER = Integer.parseInt("@buildNumber@"); + public static final String GIT_BRANCH = "@branch@"; public static final int METRICS_ID = 14649; - public static final char COLOR_CHAR = 'ยง'; + public static final char COLOR_CHAR = '\u00A7'; public static final boolean DEBUG_MODE = false; public static final boolean PRINT_ALL_PACKETS = false; @@ -55,7 +55,7 @@ public final class Constants { public static final String NTP_SERVER = "time.cloudflare.com"; public static final String INTERNAL_ERROR_MESSAGE = - "An internal error happened while handling Floodgate data." + + "An internal error happened while handling Floodgate data." + " Try logging in again or contact a server administrator if the issue persists."; public static final String UNSUPPORTED_DATA_VERSION = "Received an unsupported Floodgate data version." + diff --git a/settings.gradle.kts b/settings.gradle.kts index bcd33b65..dadaef35 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -54,9 +54,6 @@ pluginManagement { repositories { gradlePluginPortal() } - plugins { - id("net.kyori.blossom") version "1.2.0" - } includeBuild("build-logic") } From e502e0019f434813a540bbe89c872d441695d00d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 27 Dec 2022 01:08:02 +0100 Subject: [PATCH 047/113] Use weak references for injected Netty channels --- .../inject/CommonPlatformInjector.java | 17 +++--- .../inject/spigot/SpigotInjector.java | 58 ++++++++++++++----- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java b/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java index 9025ca0d..95e0a339 100644 --- a/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java +++ b/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java @@ -26,27 +26,30 @@ package org.geysermc.floodgate.inject; import io.netty.channel.Channel; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; -import lombok.AccessLevel; -import lombok.Getter; +import java.util.WeakHashMap; import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.PlatformInjector; public abstract class CommonPlatformInjector implements PlatformInjector { - @Getter(AccessLevel.PROTECTED) - private final Set injectedClients = new HashSet<>(); + private final Map injectedClients = + Collections.synchronizedMap(new WeakHashMap<>()); private final Map, InjectorAddon> addons = new HashMap<>(); protected boolean addInjectedClient(Channel channel) { - return injectedClients.add(channel); + return injectedClients.put(channel, null) != null; } public boolean removeInjectedClient(Channel channel) { - return injectedClients.remove(channel); + return injectedClients.remove(channel) != null; + } + + public Set injectedClients() { + return injectedClients.keySet(); } @Override diff --git a/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java b/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java index 2a718b0a..42b1034e 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java +++ b/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java @@ -126,30 +126,60 @@ public void removeInjection() { return; } - // remove injection from clients - for (Channel channel : getInjectedClients()) { - removeAddonsCall(channel); - } - getInjectedClients().clear(); - - // and change the list back to the original + // let's change the list back to the original first + // so that new connections are not handled through our custom list Object serverConnection = getServerConnection(); if (serverConnection != null) { Field field = ReflectionUtils.getField(serverConnection.getClass(), injectedFieldName); - List list = (List) ReflectionUtils.getValue(serverConnection, field); - if (list instanceof CustomList) { - CustomList customList = (CustomList) list; - ReflectionUtils.setValue(serverConnection, field, customList.getOriginalList()); - customList.clear(); - customList.addAll(list); + if (!findAndReplaceCustomList(serverConnection, field)) { + throw new IllegalStateException( + "Unable to remove all references of Floodgate! " + + "Reloading will very likely break Floodgate." + ); } } + // remove injection from clients + for (Channel channel : injectedClients()) { + removeAddonsCall(channel); + } + + //todo make sure that all references are removed from the channels, + // except from one AttributeKey with Floodgate player data which could be used + // after reloading + injected = false; } - public Object getServerConnection() { + /** + * Replaces all references of CustomList with the original list. + * It's entirely possible that e.g. the most recent channel map override isn't Floodgate's + */ + private boolean findAndReplaceCustomList(Object object, Field possibleListField) { + Object value = ReflectionUtils.getValue(object, possibleListField); + + if (value == null || value.getClass() == Object.class) { + return false; + } + + if (value instanceof CustomList) { + // all we have to do is replace the list with the original list. + // the original list is up-to-date, so we don't have to clear/add/whatever anything + CustomList customList = (CustomList) value; + ReflectionUtils.setValue(object, possibleListField, customList.getOriginalList()); + } + + boolean found = false; + for (Field field : value.getClass().getDeclaredFields()) { + // normally list types don't have a lot of fields, so let's just try all of them + found |= findAndReplaceCustomList(value, field); + } + + return found; + } + + private Object getServerConnection() { if (serverConnection != null) { return serverConnection; } From c84dd0cae507b1fb0205a7f4d19dab403aaa7f8a Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 27 Dec 2022 12:05:47 +0100 Subject: [PATCH 048/113] Use newSetFromMap --- .../floodgate/inject/CommonPlatformInjector.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java b/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java index 95e0a339..1547a2be 100644 --- a/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java +++ b/core/src/main/java/org/geysermc/floodgate/inject/CommonPlatformInjector.java @@ -35,21 +35,21 @@ import org.geysermc.floodgate.api.inject.PlatformInjector; public abstract class CommonPlatformInjector implements PlatformInjector { - private final Map injectedClients = - Collections.synchronizedMap(new WeakHashMap<>()); + private final Set injectedClients = + Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); private final Map, InjectorAddon> addons = new HashMap<>(); protected boolean addInjectedClient(Channel channel) { - return injectedClients.put(channel, null) != null; + return injectedClients.add(channel); } public boolean removeInjectedClient(Channel channel) { - return injectedClients.remove(channel) != null; + return injectedClients.remove(channel); } public Set injectedClients() { - return injectedClients.keySet(); + return injectedClients; } @Override From 913c85c154f8c75d198988732c1ab29ae5fb18d4 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 28 Dec 2022 02:11:26 +0100 Subject: [PATCH 049/113] Added a SkinApplyEvent that can cancel/edit the to be applied skin --- .../geysermc/floodgate/api/FloodgateApi.java | 5 + .../floodgate/api/InstanceHolder.java | 13 +- .../api/event/FloodgateEventBus.java | 31 +++++ .../api/event/FloodgateSubscriber.java | 31 +++++ .../api/event/skin/SkinApplyEvent.java | 74 ++++++++++++ .../floodgate/listener/BungeeListener.java | 6 +- .../module/BungeePlatformModule.java | 7 +- .../pluginmessage/BungeeSkinApplier.java | 114 +++++++----------- .../geysermc/floodgate/FloodgatePlatform.java | 13 +- .../geysermc/floodgate/event/EventBus.java | 7 +- .../floodgate/event/EventSubscriber.java | 3 +- .../{ => lifecycle}/PostEnableEvent.java | 2 +- .../event/{ => lifecycle}/ShutdownEvent.java | 2 +- .../event/skin/SkinApplyEventImpl.java | 67 ++++++++++ .../floodgate/link/CommonPlayerLink.java | 2 +- .../floodgate/link/PlayerLinkHolder.java | 2 +- .../floodgate/module/CommonModule.java | 16 +-- .../geysermc/floodgate/news/NewsChecker.java | 2 +- .../floodgate/player/FloodgatePlayerImpl.java | 3 +- .../pluginmessage/channel/SkinChannel.java | 13 +- .../geysermc/floodgate/skin/SkinApplier.java | 13 +- .../skin/{SkinData.java => SkinDataImpl.java} | 35 ++++-- .../floodgate/skin/SkinUploadManager.java | 13 +- .../floodgate/skin/SkinUploadSocket.java | 17 ++- .../floodgate/util/PostEnableMessages.java | 2 +- .../module/SpigotPlatformModule.java | 8 +- .../pluginmessage/SpigotSkinApplier.java | 91 +++++++------- .../module/VelocityPlatformModule.java | 7 +- .../floodgate/util/VelocitySkinApplier.java | 55 ++++++--- 29 files changed, 422 insertions(+), 232 deletions(-) create mode 100644 api/src/main/java/org/geysermc/floodgate/api/event/FloodgateEventBus.java create mode 100644 api/src/main/java/org/geysermc/floodgate/api/event/FloodgateSubscriber.java create mode 100644 api/src/main/java/org/geysermc/floodgate/api/event/skin/SkinApplyEvent.java rename core/src/main/java/org/geysermc/floodgate/event/{ => lifecycle}/PostEnableEvent.java (96%) rename core/src/main/java/org/geysermc/floodgate/event/{ => lifecycle}/ShutdownEvent.java (96%) create mode 100644 core/src/main/java/org/geysermc/floodgate/event/skin/SkinApplyEventImpl.java rename core/src/main/java/org/geysermc/floodgate/skin/{SkinData.java => SkinDataImpl.java} (66%) diff --git a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java index 0d2b0efd..999935ab 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java +++ b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java @@ -30,6 +30,7 @@ import java.util.concurrent.CompletableFuture; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; +import org.geysermc.floodgate.api.event.FloodgateEventBus; import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.unsafe.Unsafe; @@ -148,6 +149,10 @@ default CompletableFuture getUuidFor(String gamertag) { */ CompletableFuture getGamertagFor(long xuid); + default FloodgateEventBus getEventBus() { + return InstanceHolder.getEventBus(); + } + /** * Returns the instance that manages all the linking. */ diff --git a/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java b/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java index d0c6af24..159310ee 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java +++ b/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java @@ -27,6 +27,7 @@ import java.util.UUID; import lombok.Getter; +import org.geysermc.floodgate.api.event.FloodgateEventBus; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.link.PlayerLink; @@ -35,6 +36,7 @@ public final class InstanceHolder { @Getter private static FloodgateApi api; @Getter private static PlayerLink playerLink; + @Getter private static FloodgateEventBus eventBus; @Getter private static PlatformInjector injector; @Getter private static PacketHandlers packetHandlers; @@ -44,11 +46,12 @@ public final class InstanceHolder { public static boolean set( FloodgateApi floodgateApi, PlayerLink link, + FloodgateEventBus floodgateEventBus, PlatformInjector platformInjector, PacketHandlers packetHandlers, HandshakeHandlers handshakeHandlers, - UUID key) { - + UUID key + ) { if (storedKey != null) { if (!storedKey.equals(key)) { return false; @@ -59,14 +62,10 @@ public static boolean set( api = floodgateApi; playerLink = link; + eventBus = floodgateEventBus; injector = platformInjector; InstanceHolder.packetHandlers = packetHandlers; InstanceHolder.handshakeHandlers = handshakeHandlers; return true; } - - @SuppressWarnings("unchecked") - public static T castApi(Class cast) { - return (T) api; - } } diff --git a/api/src/main/java/org/geysermc/floodgate/api/event/FloodgateEventBus.java b/api/src/main/java/org/geysermc/floodgate/api/event/FloodgateEventBus.java new file mode 100644 index 00000000..935cde21 --- /dev/null +++ b/api/src/main/java/org/geysermc/floodgate/api/event/FloodgateEventBus.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.api.event; + +import org.geysermc.event.bus.EventBus; + +public interface FloodgateEventBus extends EventBus> { +} diff --git a/api/src/main/java/org/geysermc/floodgate/api/event/FloodgateSubscriber.java b/api/src/main/java/org/geysermc/floodgate/api/event/FloodgateSubscriber.java new file mode 100644 index 00000000..0d9ab473 --- /dev/null +++ b/api/src/main/java/org/geysermc/floodgate/api/event/FloodgateSubscriber.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.api.event; + +import org.geysermc.event.subscribe.Subscriber; + +public interface FloodgateSubscriber extends Subscriber { +} diff --git a/api/src/main/java/org/geysermc/floodgate/api/event/skin/SkinApplyEvent.java b/api/src/main/java/org/geysermc/floodgate/api/event/skin/SkinApplyEvent.java new file mode 100644 index 00000000..7a4b16c1 --- /dev/null +++ b/api/src/main/java/org/geysermc/floodgate/api/event/skin/SkinApplyEvent.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.api.event.skin; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.common.returnsreceiver.qual.This; +import org.geysermc.event.Cancellable; +import org.geysermc.floodgate.api.player.FloodgatePlayer; + +/** + * An event that's fired when Floodgate receives a player skin. The event will be cancelled by + * default when hasSkin is true, as Floodgate by default only applies skins when the player has no + * skin applied yet. + */ +public interface SkinApplyEvent extends Cancellable { + /** + * Returns the player that will receive the skin. + */ + @NonNull FloodgatePlayer player(); + + /** + * Returns the skin texture currently applied to the player. + */ + @Nullable SkinData currentSkin(); + + /** + * Returns the skin texture to be applied to the player. + */ + @NonNull SkinData newSkin(); + + /** + * Sets the skin texture to be applied to the player + * + * @param skinData the skin to apply + * @return this + */ + @This SkinApplyEvent newSkin(@NonNull SkinData skinData); + + interface SkinData { + /** + * Returns the value of the skin texture. + */ + @NonNull String value(); + + /** + * Returns the signature of the skin texture. + */ + @NonNull String signature(); + } +} diff --git a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java index 5aa717f8..9723cf58 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java +++ b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java @@ -48,7 +48,7 @@ import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.floodgate.skin.SkinDataImpl; import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.ReflectionUtils; @@ -130,8 +130,8 @@ public void onPostLogin(PostLoginEvent event) { // To fix the February 2 2022 Mojang authentication changes if (!config.isSendFloodgateData()) { FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); - if (player != null && !player.isLinked() && !skinApplier.hasSkin(player)) { - skinApplier.applySkin(player, new SkinData("", "")); + if (player != null && !player.isLinked()) { + skinApplier.applySkin(player, new SkinDataImpl("", "")); } } } diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java index e66fc138..4943d88c 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java +++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java @@ -70,6 +70,7 @@ protected void configure() { bind(PlatformUtils.class).to(BungeePlatformUtils.class); bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger()); bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); + bind(SkinApplier.class).to(BungeeSkinApplier.class); } @Provides @@ -121,12 +122,6 @@ public PluginMessageRegistration pluginMessageRegistration() { return new BungeePluginMessageRegistration(); } - @Provides - @Singleton - public SkinApplier skinApplier(FloodgateLogger logger) { - return new BungeeSkinApplier(logger); - } - /* DebugAddon / PlatformInjector */ diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index 3e360615..ce6105ec 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -26,68 +26,55 @@ package org.geysermc.floodgate.pluginmessage; import static com.google.common.base.Preconditions.checkNotNull; -import static org.geysermc.floodgate.util.ReflectionUtils.getConstructor; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; -import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; +import com.google.inject.Inject; +import com.google.inject.Singleton; import java.lang.reflect.Field; -import java.lang.reflect.Method; -import lombok.RequiredArgsConstructor; +import java.util.ArrayList; +import java.util.List; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.connection.LoginResult; import net.md_5.bungee.protocol.Property; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import org.geysermc.floodgate.event.EventBus; +import org.geysermc.floodgate.event.skin.SkinApplyEventImpl; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.floodgate.skin.SkinDataImpl; import org.geysermc.floodgate.util.ReflectionUtils; -@RequiredArgsConstructor +@Singleton public final class BungeeSkinApplier implements SkinApplier { - private static final Constructor LOGIN_RESULT_CONSTRUCTOR; private static final Field LOGIN_RESULT_FIELD; - private static final Method SET_PROPERTIES_METHOD; - - private static final Class PROPERTY_CLASS; - private static final Constructor PROPERTY_CONSTRUCTOR; static { - PROPERTY_CLASS = ReflectionUtils.getClassOrFallbackPrefixed( - "protocol.Property", "connection.LoginResult$Property" - ); - - LOGIN_RESULT_CONSTRUCTOR = getConstructor( - LoginResult.class, true, - String.class, String.class, Array.newInstance(PROPERTY_CLASS, 0).getClass() - ); - LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class); checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null"); - - SET_PROPERTIES_METHOD = getMethodByName(LoginResult.class, "setProperties", true); - - PROPERTY_CONSTRUCTOR = ReflectionUtils.getConstructor( - PROPERTY_CLASS, true, - String.class, String.class, String.class - ); - checkNotNull(PROPERTY_CONSTRUCTOR, "Property constructor cannot be null"); } - private final FloodgateLogger logger; + private final ProxyServer server = ProxyServer.getInstance(); + + @Inject private EventBus eventBus; + @Inject private FloodgateLogger logger; @Override - public void applySkin(FloodgatePlayer uuid, SkinData skinData) { - ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid.getCorrectUniqueId()); + public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) { + ProxiedPlayer player = server.getPlayer(floodgatePlayer.getCorrectUniqueId()); if (player == null) { return; } - InitialHandler handler = getHandler(player); - if (handler == null) { + InitialHandler handler; + try { + handler = (InitialHandler) player.getPendingConnection(); + } catch (Exception exception) { + logger.error("Incompatible Bungeecord fork detected", exception); return; } @@ -95,57 +82,46 @@ public void applySkin(FloodgatePlayer uuid, SkinData skinData) { // expected to be null since LoginResult is the data from hasJoined, // which Floodgate players don't have if (loginResult == null) { - // id and name are unused and properties will be overridden - loginResult = (LoginResult) ReflectionUtils.newInstance( - LOGIN_RESULT_CONSTRUCTOR, null, null, null - ); + // id and name are unused + loginResult = new LoginResult(null, null, new Property[0]); ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult); } - Object property = ReflectionUtils.newInstance( - PROPERTY_CONSTRUCTOR, - "textures", skinData.getValue(), skinData.getSignature() - ); + Property[] properties = loginResult.getProperties(); - Object propertyArray = Array.newInstance(PROPERTY_CLASS, 1); - Array.set(propertyArray, 0, property); + SkinData currentSkin = currentSkin(properties); - ReflectionUtils.invoke(loginResult, SET_PROPERTIES_METHOD, propertyArray); - } + SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData); + event.setCancelled(floodgatePlayer.isLinked()); - @Override - public boolean hasSkin(FloodgatePlayer fPlayer) { - ProxiedPlayer player = ProxyServer.getInstance().getPlayer(fPlayer.getCorrectUniqueId()); - if (player == null) { - return false; - } + eventBus.fire(event); - InitialHandler handler = getHandler(player); - if (handler == null) { - return false; + if (event.isCancelled()) { + return; } - LoginResult loginResult = handler.getLoginProfile(); - if (loginResult == null) { - return false; - } + loginResult.setProperties(replaceSkin(properties, event.newSkin())); + } - for (Property property : loginResult.getProperties()) { + private SkinData currentSkin(Property[] properties) { + for (Property property : properties) { if (property.getName().equals("textures")) { if (!property.getValue().isEmpty()) { - return true; + return new SkinDataImpl(property.getValue(), property.getSignature()); } } } - return false; + return null; } - private InitialHandler getHandler(ProxiedPlayer player) { - try { - return (InitialHandler) player.getPendingConnection(); - } catch (Exception exception) { - logger.error("Incompatible Bungeecord fork detected", exception); - return null; + private Property[] replaceSkin(Property[] properties, SkinData skinData) { + List list = new ArrayList<>(); + for (Property property : properties) { + if (!property.getName().equals("textures")) { + list.add(property); + } } + list.add(new Property("textures", skinData.value(), skinData.signature())); + return list.toArray(new Property[0]); } } diff --git a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java index a02b52a1..70487093 100644 --- a/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java @@ -31,14 +31,15 @@ import java.util.UUID; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.InstanceHolder; +import org.geysermc.floodgate.api.event.FloodgateEventBus; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.event.EventBus; -import org.geysermc.floodgate.event.PostEnableEvent; -import org.geysermc.floodgate.event.ShutdownEvent; +import org.geysermc.floodgate.event.lifecycle.PostEnableEvent; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.module.PostInitializeModule; public class FloodgatePlatform { @@ -52,9 +53,13 @@ public class FloodgatePlatform { public void init( FloodgateApi api, PlayerLink link, + FloodgateEventBus eventBus, PacketHandlers packetHandlers, - HandshakeHandlers handshakeHandlers) { - InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY); + HandshakeHandlers handshakeHandlers + ) { + InstanceHolder.set( + api, link, eventBus, this.injector, packetHandlers, handshakeHandlers, KEY + ); } public void enable(Module... postInitializeModules) throws RuntimeException { diff --git a/core/src/main/java/org/geysermc/floodgate/event/EventBus.java b/core/src/main/java/org/geysermc/floodgate/event/EventBus.java index abef2db2..c8e6f9bc 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/EventBus.java +++ b/core/src/main/java/org/geysermc/floodgate/event/EventBus.java @@ -25,6 +25,7 @@ package org.geysermc.floodgate.event; +import com.google.inject.Singleton; import java.util.function.BiConsumer; import java.util.function.Consumer; import org.checkerframework.checker.nullness.qual.NonNull; @@ -32,9 +33,13 @@ import org.geysermc.event.bus.impl.EventBusImpl; import org.geysermc.event.subscribe.Subscribe; import org.geysermc.event.subscribe.Subscriber; +import org.geysermc.floodgate.api.event.FloodgateEventBus; +import org.geysermc.floodgate.api.event.FloodgateSubscriber; +@Singleton @SuppressWarnings("unchecked") -public final class EventBus extends EventBusImpl> { +public final class EventBus extends EventBusImpl> + implements FloodgateEventBus { @Override protected > B makeSubscription( @NonNull Class eventClass, diff --git a/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java b/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java index e37d2fa1..f01c209b 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java +++ b/core/src/main/java/org/geysermc/floodgate/event/EventSubscriber.java @@ -30,8 +30,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.PostOrder; import org.geysermc.event.subscribe.impl.SubscriberImpl; +import org.geysermc.floodgate.api.event.FloodgateSubscriber; -public final class EventSubscriber extends SubscriberImpl { +public final class EventSubscriber extends SubscriberImpl implements FloodgateSubscriber { EventSubscriber( @NonNull Class eventClass, @NonNull Consumer handler, diff --git a/core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java b/core/src/main/java/org/geysermc/floodgate/event/lifecycle/PostEnableEvent.java similarity index 96% rename from core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java rename to core/src/main/java/org/geysermc/floodgate/event/lifecycle/PostEnableEvent.java index 0ae55e26..f274ff16 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/PostEnableEvent.java +++ b/core/src/main/java/org/geysermc/floodgate/event/lifecycle/PostEnableEvent.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Floodgate */ -package org.geysermc.floodgate.event; +package org.geysermc.floodgate.event.lifecycle; public class PostEnableEvent { } diff --git a/core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java b/core/src/main/java/org/geysermc/floodgate/event/lifecycle/ShutdownEvent.java similarity index 96% rename from core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java rename to core/src/main/java/org/geysermc/floodgate/event/lifecycle/ShutdownEvent.java index 345c9f30..30e782c5 100644 --- a/core/src/main/java/org/geysermc/floodgate/event/ShutdownEvent.java +++ b/core/src/main/java/org/geysermc/floodgate/event/lifecycle/ShutdownEvent.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Floodgate */ -package org.geysermc.floodgate.event; +package org.geysermc.floodgate.event.lifecycle; public class ShutdownEvent { } diff --git a/core/src/main/java/org/geysermc/floodgate/event/skin/SkinApplyEventImpl.java b/core/src/main/java/org/geysermc/floodgate/event/skin/SkinApplyEventImpl.java new file mode 100644 index 00000000..52148986 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/event/skin/SkinApplyEventImpl.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2022 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/Floodgate + */ + +package org.geysermc.floodgate.event.skin; + +import java.util.Objects; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.event.util.AbstractCancellable; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; +import org.geysermc.floodgate.api.player.FloodgatePlayer; + +public class SkinApplyEventImpl extends AbstractCancellable implements SkinApplyEvent { + private final FloodgatePlayer player; + private final SkinData currentSkin; + private SkinData newSkin; + + public SkinApplyEventImpl( + @NonNull FloodgatePlayer player, + @Nullable SkinData currentSkin, + @NonNull SkinData newSkin + ) { + this.player = Objects.requireNonNull(player); + this.currentSkin = currentSkin; + this.newSkin = Objects.requireNonNull(newSkin); + } + + @Override + public @NonNull FloodgatePlayer player() { + return player; + } + + public @Nullable SkinData currentSkin() { + return currentSkin; + } + + public @NonNull SkinData newSkin() { + return newSkin; + } + + public SkinApplyEventImpl newSkin(@NonNull SkinData skinData) { + this.newSkin = Objects.requireNonNull(skinData); + return this; + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java index f1bfb912..9324a097 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java +++ b/core/src/main/java/org/geysermc/floodgate/link/CommonPlayerLink.java @@ -43,7 +43,7 @@ import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.database.config.DatabaseConfig; import org.geysermc.floodgate.database.config.DatabaseConfigLoader; -import org.geysermc.floodgate.event.ShutdownEvent; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.util.InjectorHolder; @Listener diff --git a/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java b/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java index 618c9b27..a91ba679 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java +++ b/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java @@ -51,7 +51,7 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig.PlayerLinkConfig; -import org.geysermc.floodgate.event.ShutdownEvent; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.InjectorHolder; import org.geysermc.floodgate.util.Utils; diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index c597922c..500cad26 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -43,6 +43,7 @@ import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi; +import org.geysermc.floodgate.api.event.FloodgateEventBus; import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.link.PlayerLink; @@ -57,14 +58,13 @@ import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; import org.geysermc.floodgate.event.EventBus; -import org.geysermc.floodgate.event.ShutdownEvent; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher; import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.link.PlayerLinkHolder; import org.geysermc.floodgate.packet.PacketHandlersImpl; import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; -import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.HttpClient; @@ -77,6 +77,7 @@ public class CommonModule extends AbstractModule { @Override protected void configure() { bind(EventBus.class).toInstance(eventBus); + bind(FloodgateEventBus.class).to(EventBus.class); // register every class that has the Listener annotation bindListener(new ListenerAnnotationMatcher(), new TypeListener() { @Override @@ -164,17 +165,6 @@ public PluginMessageManager pluginMessageManager() { return new PluginMessageManager(); } - @Provides - @Singleton - public SkinUploadManager skinUploadManager( - FloodgateApi api, - SkinApplier skinApplier, - FloodgateLogger logger) { - SkinUploadManager manager = new SkinUploadManager(api, skinApplier, logger); - eventBus.register(manager); - return manager; - } - @Provides @Singleton @Named("gitBranch") diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index cdbeed07..bff279d0 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -41,7 +41,7 @@ import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.command.util.Permission; -import org.geysermc.floodgate.event.ShutdownEvent; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.news.data.AnnouncementData; import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.CheckAfterData; diff --git a/core/src/main/java/org/geysermc/floodgate/player/FloodgatePlayerImpl.java b/core/src/main/java/org/geysermc/floodgate/player/FloodgatePlayerImpl.java index acfcab75..5945f66e 100644 --- a/core/src/main/java/org/geysermc/floodgate/player/FloodgatePlayerImpl.java +++ b/core/src/main/java/org/geysermc/floodgate/player/FloodgatePlayerImpl.java @@ -32,7 +32,6 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.api.InstanceHolder; import org.geysermc.floodgate.api.ProxyFloodgateApi; import org.geysermc.floodgate.api.handshake.HandshakeData; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -72,7 +71,7 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer { private Map stringToPropertyKey; static FloodgatePlayerImpl from(BedrockData data, HandshakeData handshakeData) { - FloodgateApi api = InstanceHolder.getApi(); + FloodgateApi api = FloodgateApi.getInstance(); UUID javaUniqueId = Utils.getJavaUuid(data.getXuid()); diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java index 02f0161b..8e9e64b0 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java @@ -25,7 +25,6 @@ package org.geysermc.floodgate.pluginmessage.channel; -import com.google.gson.JsonObject; import com.google.inject.Inject; import java.nio.charset.StandardCharsets; import java.util.UUID; @@ -36,7 +35,7 @@ import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.pluginmessage.PluginMessageChannel; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.floodgate.skin.SkinDataImpl; public class SkinChannel implements PluginMessageChannel { @Inject private FloodgateApi api; @@ -89,18 +88,10 @@ public Result handleServerCall(byte[] data, UUID playerUuid, String playerUserna return Result.kick("Got invalid skin data"); } - if (floodgatePlayer.isLinked() || skinApplier.hasSkin(floodgatePlayer)) { - return Result.handled(); - } - String value = split[0]; String signature = split[1]; - JsonObject result = new JsonObject(); - result.addProperty("value", value); - result.addProperty("signature", signature); - - SkinData skinData = new SkinData(value, signature); + SkinDataImpl skinData = new SkinDataImpl(value, signature); floodgatePlayer.addProperty(PropertyKey.SKIN_UPLOADED, skinData); skinApplier.applySkin(floodgatePlayer, skinData); diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java index 93dc3cb4..c8e7684c 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java @@ -25,6 +25,8 @@ package org.geysermc.floodgate.skin; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.player.FloodgatePlayer; public interface SkinApplier { @@ -34,14 +36,5 @@ public interface SkinApplier { * @param floodgatePlayer player to apply skin to * @param skinData data for skin to apply to player */ - void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData); - - /** - * Check if a {@link FloodgatePlayer player} currently - * has a skin applied. - * - * @param floodgatePlayer player to check skin of - * @return if player has a skin - */ - boolean hasSkin(FloodgatePlayer floodgatePlayer); + void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData); } diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinData.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java similarity index 66% rename from core/src/main/java/org/geysermc/floodgate/skin/SkinData.java rename to core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java index 84162710..9f44af79 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinData.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java @@ -26,22 +26,33 @@ package org.geysermc.floodgate.skin; import com.google.gson.JsonObject; -import lombok.Getter; -import lombok.RequiredArgsConstructor; +import java.util.Objects; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; -@Getter -@RequiredArgsConstructor -public class SkinData { +public class SkinDataImpl implements SkinData { private final String value; private final String signature; + public SkinDataImpl(@NonNull String value, @NonNull String signature) { + this.value = Objects.requireNonNull(value); + this.signature = Objects.requireNonNull(signature); + } + public static SkinData from(JsonObject data) { - if (data.has("signature") && !data.get("signature").isJsonNull()) { - return new SkinData( - data.get("value").getAsString(), - data.get("signature").getAsString() - ); - } - return new SkinData(data.get("value").getAsString(), null); + return new SkinDataImpl( + data.get("value").getAsString(), + data.get("signature").getAsString() + ); + } + + @Override + public @NonNull String value() { + return value; + } + + @Override + public @NonNull String signature() { + return signature; } } diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java index 1603723d..61db1ab6 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadManager.java @@ -25,25 +25,26 @@ package org.geysermc.floodgate.skin; +import com.google.inject.Inject; +import com.google.inject.Singleton; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import lombok.AllArgsConstructor; import org.geysermc.event.Listener; import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.event.ShutdownEvent; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; @Listener -@AllArgsConstructor +@Singleton public final class SkinUploadManager { private final Int2ObjectMap connections = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); - private final FloodgateApi api; - private final SkinApplier applier; - private final FloodgateLogger logger; + @Inject private FloodgateApi api; + @Inject private SkinApplier applier; + @Inject private FloodgateLogger logger; public void addConnectionIfNeeded(int id, String verifyCode) { connections.computeIfAbsent(id, (ignored) -> { diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java index c933d7f0..5018f8fa 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java @@ -35,6 +35,7 @@ import javax.net.ssl.SSLException; import lombok.Getter; import org.geysermc.floodgate.api.FloodgateApi; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.PropertyKey; @@ -61,8 +62,8 @@ public SkinUploadSocket( SkinUploadManager uploadManager, FloodgateApi api, SkinApplier applier, - FloodgateLogger logger) { - + FloodgateLogger logger + ) { super(getWebsocketUri(id, verifyCode)); this.id = id; this.verifyCode = verifyCode; @@ -83,7 +84,7 @@ private static URI getWebsocketUri(int id, String verifyCode) { } @Override - public void onOpen(ServerHandshake handshakedata) { + public void onOpen(ServerHandshake ignored) { setConnectionLostTimeout(11); } @@ -114,10 +115,14 @@ public void onMessage(String data) { player.getCorrectUsername()); return; } - if (!player.isLinked() && !applier.hasSkin(player)) { - SkinData skinData = SkinData.from(message.getAsJsonObject("data")); + + SkinData skinData = SkinDataImpl.from(message.getAsJsonObject("data")); + applier.applySkin(player, skinData); + + // legacy stuff, + // will be removed shortly after or during the Floodgate-Geyser integration + if (!player.isLinked()) { player.addProperty(PropertyKey.SKIN_UPLOADED, skinData); - applier.applySkin(player, skinData); } } break; diff --git a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java index baadb195..70bcdc30 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java +++ b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java @@ -32,7 +32,7 @@ import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.event.PostEnableEvent; +import org.geysermc.floodgate.event.lifecycle.PostEnableEvent; @AutoBind @Listener diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index 1654badb..cd7e03b1 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -61,9 +61,11 @@ public final class SpigotPlatformModule extends AbstractModule { @Override protected void configure() { + bind(SpigotPlugin.class).toInstance(plugin); bind(PlatformUtils.class).to(SpigotPlatformUtils.class); bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger()); bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); + bind(SkinApplier.class).to(SpigotSkinApplier.class); } @Provides @@ -142,12 +144,6 @@ public PluginMessageRegistration pluginMessageRegister() { return new SpigotPluginMessageRegistration(plugin); } - @Provides - @Singleton - public SkinApplier skinApplier(SpigotVersionSpecificMethods versionSpecificMethods) { - return new SpigotSkinApplier(versionSpecificMethods, plugin); - } - @Provides @Singleton public SpigotVersionSpecificMethods versionSpecificMethods() { diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index edc57279..fa599f40 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -25,71 +25,48 @@ package org.geysermc.floodgate.pluginmessage; +import com.google.inject.Inject; +import com.google.inject.Singleton; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.SpigotPlugin; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import org.geysermc.floodgate.event.EventBus; +import org.geysermc.floodgate.event.skin.SkinApplyEventImpl; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.floodgate.skin.SkinDataImpl; import org.geysermc.floodgate.util.ClassNames; import org.geysermc.floodgate.util.ReflectionUtils; import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; +@Singleton public final class SpigotSkinApplier implements SkinApplier { - private final SpigotVersionSpecificMethods versionSpecificMethods; - private final SpigotPlugin plugin; - - public SpigotSkinApplier( - SpigotVersionSpecificMethods versionSpecificMethods, - SpigotPlugin plugin) { - this.versionSpecificMethods = versionSpecificMethods; - this.plugin = plugin; - } + @Inject private SpigotVersionSpecificMethods versionSpecificMethods; + @Inject private SpigotPlugin plugin; + @Inject private EventBus eventBus; @Override - public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) { + public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) { applySkin0(floodgatePlayer, skinData, true); } - @Override - public boolean hasSkin(FloodgatePlayer floodgatePlayer) { - Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId()); - - if (player == null) { - return false; - } - - GameProfile profile = ReflectionUtils.castedInvoke(player, ClassNames.GET_PROFILE_METHOD); - if (profile == null) { - throw new IllegalStateException("The GameProfile cannot be null! " + player.getName()); - } - - // Need to be careful here - getProperties() returns an authlib PropertyMap, which extends - // MultiMap from Guava. Floodgate relocates Guava. - for (Property textures : profile.getProperties().get("textures")) { - if (!textures.getValue().isEmpty()) { - return true; - } - } - return false; - } - private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, boolean firstTry) { Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId()); // player is probably not logged in yet if (player == null) { if (firstTry) { - Bukkit.getScheduler().runTaskLater(plugin, - () -> { - if (!hasSkin(floodgatePlayer)) { - applySkin0(floodgatePlayer, skinData, false); - } - }, - 10 * 20); + Bukkit.getScheduler().runTaskLater( + plugin, + () -> applySkin0(floodgatePlayer, skinData, false), + 10 * 20 + ); } return; } @@ -100,11 +77,22 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool throw new IllegalStateException("The GameProfile cannot be null! " + player.getName()); } + // Need to be careful here - getProperties() returns an authlib PropertyMap, which extends + // MultiMap from Guava. Floodgate relocates Guava. PropertyMap properties = profile.getProperties(); - properties.removeAll("textures"); - Property property = new Property("textures", skinData.getValue(), skinData.getSignature()); - properties.put("textures", property); + SkinData currentSkin = currentSkin(properties); + + SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData); + event.setCancelled(floodgatePlayer.isLinked()); + + eventBus.fire(event); + + if (event.isCancelled()) { + return; + } + + replaceSkin(properties, event.newSkin()); // By running as a task, we don't run into async issues plugin.getServer().getScheduler().runTask(plugin, () -> { @@ -116,4 +104,19 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool } }); } + + private SkinData currentSkin(PropertyMap properties) { + for (Property texture : properties.get("textures")) { + if (!texture.getValue().isEmpty()) { + return new SkinDataImpl(texture.getValue(), texture.getSignature()); + } + } + return null; + } + + private void replaceSkin(PropertyMap properties, SkinData skinData) { + properties.removeAll("textures"); + Property property = new Property("textures", skinData.value(), skinData.signature()); + properties.put("textures", property); + } } diff --git a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java index b5244c3a..fb412b47 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java +++ b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java @@ -69,6 +69,7 @@ protected void configure() { bind(CommandUtil.class).to(VelocityCommandUtil.class); bind(PlatformUtils.class).to(VelocityPlatformUtils.class); bind(FloodgateLogger.class).to(Slf4jFloodgateLogger.class); + bind(SkinApplier.class).to(VelocitySkinApplier.class); } @Provides @@ -112,12 +113,6 @@ public PluginMessageRegistration pluginMessageRegistration(ProxyServer proxy) { return new VelocityPluginMessageRegistration(proxy); } - @Provides - @Singleton - public SkinApplier skinApplier(ProxyServer server) { - return new VelocitySkinApplier(server); - } - /* DebugAddon / PlatformInjector */ diff --git a/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java b/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java index c2c66d2f..f9818cbc 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java +++ b/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java @@ -25,43 +25,60 @@ package org.geysermc.floodgate.util; -import com.velocitypowered.api.proxy.Player; +import com.google.inject.Inject; +import com.google.inject.Singleton; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.util.GameProfile.Property; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import lombok.RequiredArgsConstructor; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import org.geysermc.floodgate.event.EventBus; +import org.geysermc.floodgate.event.skin.SkinApplyEventImpl; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.floodgate.skin.SkinDataImpl; -@RequiredArgsConstructor +@Singleton public class VelocitySkinApplier implements SkinApplier { - private final ProxyServer server; + @Inject private ProxyServer server; + @Inject private EventBus eventBus; @Override - public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) { + public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) { server.getPlayer(floodgatePlayer.getCorrectUniqueId()).ifPresent(player -> { List properties = new ArrayList<>(player.getGameProfileProperties()); - properties.add(new Property("textures", skinData.getValue(), skinData.getSignature())); + + SkinData currentSkin = currentSkin(properties); + + SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData); + event.setCancelled(floodgatePlayer.isLinked()); + + eventBus.fire(event); + + if (event.isCancelled()) { + return; + } + + replaceSkin(properties, event.newSkin()); player.setGameProfileProperties(properties); }); } - @Override - public boolean hasSkin(FloodgatePlayer floodgatePlayer) { - Optional player = server.getPlayer(floodgatePlayer.getCorrectUniqueId()); - - if (player.isPresent()) { - for (Property property : player.get().getGameProfileProperties()) { - if (property.getName().equals("textures")) { - if (!property.getValue().isEmpty()) { - return true; - } + private SkinData currentSkin(List properties) { + for (Property property : properties) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return new SkinDataImpl(property.getValue(), property.getSignature()); } } } - return false; + return null; + } + + private void replaceSkin(List properties, SkinData skinData) { + properties.removeIf(property -> property.getName().equals("textures")); + properties.add(new Property("textures", skinData.value(), skinData.signature())); } } From 0c4b953cdb5193f6e275e19e51724b6599520383 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 28 Dec 2022 13:24:42 +0100 Subject: [PATCH 050/113] Use a common ScheduledThreadPool and make the player map concurrent --- .../floodgate/api/SimpleFloodgateApi.java | 4 ++-- .../floodgate/module/CommonModule.java | 16 ++++++++++++-- .../geysermc/floodgate/news/NewsChecker.java | 18 +++------------- .../floodgate/util/PostEnableMessages.java | 21 +++++++++++-------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java index 0309eb2d..5ef49e46 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java @@ -32,10 +32,10 @@ import com.google.gson.JsonObject; import com.google.inject.Inject; import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; @@ -51,7 +51,7 @@ import org.geysermc.floodgate.util.Utils; public class SimpleFloodgateApi implements FloodgateApi { - private final Map players = new HashMap<>(); + private final Map players = new ConcurrentHashMap<>(); private final Cache pendingRemove = CacheBuilder.newBuilder() .expireAfterWrite(20, TimeUnit.SECONDS) diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 500cad26..ff45c89d 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -38,6 +38,7 @@ import java.nio.file.Path; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import lombok.RequiredArgsConstructor; import org.geysermc.event.PostOrder; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; @@ -87,8 +88,19 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { }); ExecutorService commonPool = Executors.newCachedThreadPool(); - eventBus.subscribe(ShutdownEvent.class, ignored -> commonPool.shutdown(), PostOrder.LAST); - bind(ExecutorService.class).annotatedWith(Names.named("commonPool")).toInstance(commonPool); + ScheduledExecutorService commonScheduledPool = Executors.newSingleThreadScheduledExecutor(); + + eventBus.subscribe(ShutdownEvent.class, ignored -> { + commonPool.shutdown(); + commonScheduledPool.shutdown(); + }, PostOrder.LAST); + + bind(ExecutorService.class) + .annotatedWith(Names.named("commonPool")) + .toInstance(commonPool); + bind(ScheduledExecutorService.class) + .annotatedWith(Names.named("commonScheduledPool")) + .toInstance(commonScheduledPool); bind(HttpClient.class).in(Singleton.class); diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index bff279d0..40358247 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -34,14 +34,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.geysermc.event.Listener; -import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.command.util.Permission; -import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.news.data.AnnouncementData; import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.CheckAfterData; @@ -52,10 +48,11 @@ import org.geysermc.floodgate.util.HttpClient.HttpResponse; @AutoBind -@Listener public class NewsChecker { - private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); private final Map activeNewsItems = new HashMap<>(); + @Inject + @Named("commonScheduledPool") + private ScheduledExecutorService executorService; @Inject private CommandUtil commandUtil; @@ -199,15 +196,6 @@ public void addNews(NewsItem item) { activateNews(item); } - public void shutdown() { - executorService.shutdown(); - } - - @Subscribe - public void onShutdown(ShutdownEvent ignored) { - shutdown(); - } - private void activateNews(NewsItem item) { for (NewsItemAction action : item.getActions()) { handleNewsItem(null, item, action); diff --git a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java index 70bcdc30..e526c470 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java +++ b/core/src/main/java/org/geysermc/floodgate/util/PostEnableMessages.java @@ -26,8 +26,11 @@ package org.geysermc.floodgate.util; import com.google.inject.Inject; +import com.google.inject.name.Named; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import org.geysermc.event.Listener; import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.logger.FloodgateLogger; @@ -41,6 +44,9 @@ public final class PostEnableMessages { @Inject private FloodgateConfig config; @Inject private FloodgateLogger logger; + @Inject + @Named("commonScheduledPool") + private ScheduledExecutorService executorService; public void add(String[] message, Object... args) { StringBuilder builder = new StringBuilder(); @@ -93,14 +99,11 @@ private void registerPrefixMessages() { @Subscribe public void onPostEnable(PostEnableEvent ignored) { - new Thread(() -> { - // normally proxies don't have a lot of plugins, so proxies don't need to sleep as long - try { - Thread.sleep(config.isProxy() ? 2000 : 5000); - } catch (InterruptedException ignored1) { - } - - messages.forEach(logger::warn); - }).start(); + // normally proxies don't have a lot of plugins, so proxies don't need to sleep as long + executorService.schedule( + () -> messages.forEach(logger::warn), + config.isProxy() ? 2 : 5, + TimeUnit.SECONDS + ); } } From eb8989b4005bbfa4707a80f01461e69b75f3d5b8 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 29 Dec 2022 00:31:48 +0100 Subject: [PATCH 051/113] Don't try to remove all injector references --- .../inject/spigot/SpigotInjector.java | 55 +++++++------------ .../module/SpigotPlatformModule.java | 7 +-- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java b/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java index 42b1034e..17812624 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java +++ b/spigot/src/main/java/org/geysermc/floodgate/inject/spigot/SpigotInjector.java @@ -25,6 +25,8 @@ package org.geysermc.floodgate.inject.spigot; +import com.google.inject.Inject; +import com.google.inject.Singleton; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; @@ -36,13 +38,15 @@ import java.lang.reflect.Type; import java.util.List; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.util.ClassNames; import org.geysermc.floodgate.util.ReflectionUtils; -@RequiredArgsConstructor +@Singleton public final class SpigotInjector extends CommonPlatformInjector { + @Inject private FloodgateLogger logger; + private Object serverConnection; private String injectedFieldName; @@ -131,13 +135,23 @@ public void removeInjection() { Object serverConnection = getServerConnection(); if (serverConnection != null) { Field field = ReflectionUtils.getField(serverConnection.getClass(), injectedFieldName); + Object value = ReflectionUtils.getValue(serverConnection, field); - if (!findAndReplaceCustomList(serverConnection, field)) { - throw new IllegalStateException( - "Unable to remove all references of Floodgate! " + - "Reloading will very likely break Floodgate." - ); + if (value instanceof CustomList) { + // all we have to do is replace the list with the original list. + // the original list is up-to-date, so we don't have to clear/add/whatever anything + CustomList customList = (CustomList) value; + ReflectionUtils.setValue(serverConnection, field, customList.getOriginalList()); + return; } + + // we could replace all references of CustomList that are directly in 'value', but that + // only brings you so far. ProtocolLib for example stores the original value + // (which would be our CustomList e.g.) in a separate object + logger.debug( + "Unable to remove all references of Floodgate due to {}! ", + value.getClass().getName() + ); } // remove injection from clients @@ -152,33 +166,6 @@ public void removeInjection() { injected = false; } - /** - * Replaces all references of CustomList with the original list. - * It's entirely possible that e.g. the most recent channel map override isn't Floodgate's - */ - private boolean findAndReplaceCustomList(Object object, Field possibleListField) { - Object value = ReflectionUtils.getValue(object, possibleListField); - - if (value == null || value.getClass() == Object.class) { - return false; - } - - if (value instanceof CustomList) { - // all we have to do is replace the list with the original list. - // the original list is up-to-date, so we don't have to clear/add/whatever anything - CustomList customList = (CustomList) value; - ReflectionUtils.setValue(object, possibleListField, customList.getOriginalList()); - } - - boolean found = false; - for (Field field : value.getClass().getDeclaredFields()) { - // normally list types don't have a lot of fields, so let's just try all of them - found |= findAndReplaceCustomList(value, field); - } - - return found; - } - private Object getServerConnection() { if (serverConnection != null) { return serverConnection; diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index 1654badb..d809701f 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -62,6 +62,7 @@ public final class SpigotPlatformModule extends AbstractModule { @Override protected void configure() { bind(PlatformUtils.class).to(SpigotPlatformUtils.class); + bind(CommonPlatformInjector.class).to(SpigotInjector.class); bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger()); bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class); } @@ -96,12 +97,6 @@ public ListenerRegistration listenerRegistration() { DebugAddon / PlatformInjector */ - @Provides - @Singleton - public CommonPlatformInjector platformInjector() { - return new SpigotInjector(); - } - @Provides @Named("packetEncoder") public String packetEncoder() { From da97a0f073cab5b0409ea12f2a1195a998fa7896 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 12 Feb 2023 11:35:32 +0100 Subject: [PATCH 052/113] Add branch name when not master, simplify publish, use GitHub Actions And updated Gradle --- .github/workflows/build.yml | 30 +++++++++++++++++ build-logic/build.gradle.kts | 4 +-- build-logic/src/main/kotlin/extensions.kt | 20 ++++++------ .../floodgate.base-conventions.gradle.kts | 27 +++++++++------- .../floodgate.publish-conventions.gradle.kts | 32 ++++--------------- .../floodgate/util/ReflectionUtils.java | 4 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 10 +++--- settings.gradle.kts | 5 +++ 9 files changed, 79 insertions(+), 55 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..6fb75dec --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,30 @@ +name: Build + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: actions/setup-java@v3 + with: + java-version: 8 + distribution: temurin + + - name: Build + uses: gradle/gradle-build-action@v2 + with: + arguments: build + + - name: Publish + uses: gradle/gradle-build-action@v2 + env: + ORG_GRADLE_PROJECT_geysermcUsername: "${{ secrets.DEPLOY_USER }}" + ORG_GRADLE_PROJECT_geysermcPassword: "${{ secrets.DEPLOY_PASS }}" + with: + arguments: publish \ No newline at end of file diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 75f6eda2..6200d2c9 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -9,8 +9,8 @@ repositories { } dependencies { - implementation("net.kyori", "indra-common", "2.0.6") - implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1") + implementation("net.kyori", "indra-common", "3.0.1") + implementation("net.kyori", "indra-git", "3.0.1") implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1") implementation("gradle.plugin.org.jetbrains.gradle.plugin.idea-ext", "gradle-idea-ext", "1.1.7") } diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 54158d84..cbb5e8a8 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -28,9 +28,6 @@ import org.gradle.api.Project import org.gradle.api.artifacts.ProjectDependency import org.gradle.kotlin.dsl.the -fun Project.isSnapshot(): Boolean = - version.toString().endsWith("-SNAPSHOT") - fun Project.fullVersion(): String { var version = version.toString() if (version.endsWith("-SNAPSHOT")) { @@ -42,14 +39,19 @@ fun Project.fullVersion(): String { fun Project.lastCommitHash(): String? = the().commit()?.name?.substring(0, 7) -// retrieved from https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project -// some properties might be specific to Jenkins fun Project.branchName(): String = - System.getenv("GIT_BRANCH") ?: "local/dev" -fun Project.buildNumber(): Int = - Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") + the().branchName() ?: System.getenv("BRANCH_NAME") ?: "local/dev" + +fun Project.shouldAddBranchName(): Boolean = + System.getenv("IGNORE_BRANCH")?.toBoolean() ?: (branchName() !in arrayOf("master", "local/dev")) + +fun Project.versionWithBranchName(): String = + branchName().replace(Regex("[^0-9A-Za-z-_]"), "-") + '-' + version + +fun buildNumber(): Int = + System.getenv("BUILD_NUMBER")?.let { Integer.parseInt(it) } ?: -1 -fun Project.buildNumberAsString(): String = +fun buildNumberAsString(): String = buildNumber().takeIf { it != -1 }?.toString() ?: "??" val providedDependencies = mutableMapOf>>() diff --git a/build-logic/src/main/kotlin/floodgate.base-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.base-conventions.gradle.kts index 0dba1832..f1d9ab8f 100644 --- a/build-logic/src/main/kotlin/floodgate.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.base-conventions.gradle.kts @@ -1,7 +1,7 @@ plugins { `java-library` - `maven-publish` // id("net.ltgt.errorprone") + id("net.kyori.indra") id("net.kyori.indra.git") } @@ -9,6 +9,21 @@ dependencies { compileOnly("org.checkerframework", "checker-qual", Versions.checkerQual) } +indra { + github("GeyserMC", "Floodgate") { + ci(true) + issues(true) + scm(true) + } + mitLicense() + + javaVersions { + // without toolchain & strictVersion sun.misc.Unsafe won't be found + minimumToolchain(8) + strictVersions(true) + } +} + tasks { processResources { filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) { @@ -22,14 +37,4 @@ tasks { ) } } - compileJava { - options.encoding = Charsets.UTF_8.name() - } -} - -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - - withSourcesJar() } \ No newline at end of file diff --git a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts index ad119489..39e180ae 100644 --- a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts @@ -1,33 +1,15 @@ plugins { id("floodgate.shadow-conventions") - id("com.jfrog.artifactory") - id("maven-publish") + id("net.kyori.indra.publishing") } -publishing { - publications { - create("mavenJava") { - groupId = project.group as String - artifactId = project.name - version = project.version as String - - from(components["java"]) +indra { + configurePublications { + if (shouldAddBranchName()) { + version = versionWithBranchName() } } -} -artifactory { - setContextUrl("https://repo.opencollab.dev/artifactory") - publish { - repository { - setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases") - setMavenCompatible(true) - } - defaults { - publications("mavenJava") - setPublishArtifacts(true) - setPublishPom(true) - setPublishIvy(false) - } - } + publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/artifactory/maven-snapshots") + publishReleasesTo("geysermc", "https://repo.opencollab.dev/artifactory/maven-releases") } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java index dfbc9d6a..709dfd43 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/ReflectionUtils.java @@ -287,7 +287,7 @@ public static Object getValue(Object instance, String fieldName) { } /** - * Get the value of a field and cast it to . + * Get the value of a field and cast it to T. * * @param instance the instance to get the value from * @param field the field to get the value from @@ -301,7 +301,7 @@ public static T getCastedValue(Object instance, Field field) { } /** - * Get the value of a field and cast it to . + * Get the value of a field and cast it to T. * * @param instance the instance to get the value from * @param fieldName the field to get the value from diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e5897..070cb702 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c7873..c53aefaa 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright ยฉ 2015-2021 the original authors. +# Copyright ฉ 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, -# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; -# * compound commands having a testable exit status, especially ยซcaseยป; -# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# * expansions ซ$varป, ซ${var}ป, ซ${var:-default}ป, ซ${var+SET}ป, +# ซ${var#prefix}ป, ซ${var%suffix}ป, and ซ$( cmd )ป; +# * compound commands having a testable exit status, especially ซcaseป; +# * various built-in commands including ซcommandป, ซsetป, and ซulimitป. # # Important for patching: # diff --git a/settings.gradle.kts b/settings.gradle.kts index dadaef35..30992cbc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,4 @@ +@file:Suppress("UnstableApiUsage") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") dependencyResolutionManagement { @@ -54,6 +55,10 @@ pluginManagement { repositories { gradlePluginPortal() } + plugins { + id("net.kyori.indra") + id("net.kyori.indra.git") + } includeBuild("build-logic") } From 4f8a83c0df9843db9c530efb8e38efe54cb51eaa Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 12 Feb 2023 11:36:03 +0100 Subject: [PATCH 053/113] Remove Jenkinsfile --- Jenkinsfile | 112 ---------------------------------------------------- 1 file changed, 112 deletions(-) delete mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index b52cca93..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,112 +0,0 @@ -pipeline { - agent any - tools { - gradle 'Gradle 7' - jdk 'Java 8' - } - options { - buildDiscarder(logRotator(artifactNumToKeepStr: '5')) - } - stages { - stage ('Build') { - steps { - sh 'git submodule update --init --recursive' - rtGradleRun( - usesPlugin: true, - tool: 'Gradle 7', - buildFile: 'build.gradle.kts', - tasks: 'clean build', - ) - } - post { - success { - archiveArtifacts artifacts: '**/build/libs/floodgate-*.jar', - excludes: '**/floodgate-parent-*.jar,**/floodgate-api.jar,**/floodgate-core.jar', - fingerprint: true - } - } - } - - stage ('Deploy') { - when { - anyOf { - branch "master" - branch "development" - } - } - - steps { - rtGradleDeployer( - id: "GRADLE_DEPLOYER", - serverId: "opencollab-artifactory", - releaseRepo: "maven-releases", - snapshotRepo: "maven-snapshots" - ) - rtGradleResolver( - id: "GRADLE_RESOLVER", - serverId: "opencollab-artifactory" - ) - rtGradleRun( - usesPlugin: true, - tool: 'Gradle 7', - rootDir: "", - useWrapper: true, - buildFile: 'build.gradle.kts', - tasks: 'artifactoryPublish', - deployerId: "GRADLE_DEPLOYER", - resolverId: "GRADLE_RESOLVER" - ) - rtPublishBuildInfo( - serverId: "opencollab-artifactory" - ) - } - } - } - - post { - always { - script { - def changeLogSets = currentBuild.changeSets - def message = "**Changes:**" - - if (changeLogSets.size() == 0) { - message += "\n*No changes.*" - } else { - def repositoryUrl = scm.userRemoteConfigs[0].url.replace(".git", "") - def count = 0; - def extra = 0; - for (int i = 0; i < changeLogSets.size(); i++) { - def entries = changeLogSets[i].items - for (int j = 0; j < entries.length; j++) { - if (count <= 10) { - def entry = entries[j] - def commitId = entry.commitId.substring(0, 6) - message += "\n - [`${commitId}`](${repositoryUrl}/commit/${entry.commitId}) ${entry.msg}" - count++ - } else { - extra++; - } - } - } - - if (extra != 0) { - message += "\n - ${extra} more commits" - } - } - - env.changes = message - } - deleteDir() - withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { - discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Floodgate)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK - } - } - success { - script { - if (env.BRANCH_NAME == 'master') { - build propagate: false, wait: false, job: 'GeyserMC/Floodgate-Fabric/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)] - } - } - } - } -} \ No newline at end of file From b1f1a2be933a736241da4bd7b190076e7f9d9a9a Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 13 Feb 2023 21:49:28 +0100 Subject: [PATCH 054/113] Retrieve version from gradle.properties --- build.gradle.kts | 2 +- gradle.properties | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9eac848e..da89fe19 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { allprojects { group = "org.geysermc.floodgate" - version = "2.2.1-SNAPSHOT" + version = property("version")!! description = "Allows Bedrock players to join Java edition servers while keeping the server in online mode" } diff --git a/gradle.properties b/gradle.properties index af7d8325..af961a84 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,5 @@ org.gradle.configureondemand=true org.gradle.caching=true -org.gradle.parallel=true \ No newline at end of file +org.gradle.parallel=true + +version=2.2.2-SNAPSHOT \ No newline at end of file From 7ea41b264838e10c960f73dba73c58f015396e6c Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 13 Feb 2023 21:51:07 +0100 Subject: [PATCH 055/113] Let's see if the setup-java action's cache is helpful & fixed building --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6fb75dec..8e9b890a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,7 @@ jobs: with: java-version: 8 distribution: temurin + cache: gradle - name: Build uses: gradle/gradle-build-action@v2 @@ -24,7 +25,7 @@ jobs: - name: Publish uses: gradle/gradle-build-action@v2 env: - ORG_GRADLE_PROJECT_geysermcUsername: "${{ secrets.DEPLOY_USER }}" - ORG_GRADLE_PROJECT_geysermcPassword: "${{ secrets.DEPLOY_PASS }}" + ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} + ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} with: arguments: publish \ No newline at end of file From 64b1d9c10857b239476b368424c8a93af401aa87 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 13 Feb 2023 21:01:37 +0000 Subject: [PATCH 056/113] Add publishing to downloads site (#385) * Add publishing to downloads site * Only publish to Downloads API when branch is master and status success --------- Co-authored-by: Tim203 --- .github/workflows/build.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e9b890a..5dda57f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,10 +22,30 @@ jobs: with: arguments: build - - name: Publish + - name: Publish to Maven Repository uses: gradle/gradle-build-action@v2 env: ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} with: - arguments: publish \ No newline at end of file + arguments: publish + + - name: Publish to Downloads API + if: ${{ github.ref_name == "master" && job.status == "success" }} + shell: bash + run: | + # Save the private key to a file + echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa + chmod 600 id_ecdsa + + # Get the version from gradle.properties + version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + + # Copy over artifacts + scp -B -o StrictHostKeyChecking=no -i id_ecdsa **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/ + + # Remove un-needed artifacts + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ~/files/floodgate-parent-*.jar ~/files/floodgate-api.jar ~/files/floodgate-core.jar + + # Run the build script + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_ID $GITHUB_SHA From d7e35ae0359df0e53ee52883a2fb086d1f12bcc3 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 13 Feb 2023 22:04:54 +0100 Subject: [PATCH 057/113] Notify Discord after building & fixed building --- .github/workflows/build.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5dda57f6..40edc4fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,6 +23,7 @@ jobs: arguments: build - name: Publish to Maven Repository + if: ${{ job.status == 'success' }} uses: gradle/gradle-build-action@v2 env: ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} @@ -31,7 +32,7 @@ jobs: arguments: publish - name: Publish to Downloads API - if: ${{ github.ref_name == "master" && job.status == "success" }} + if: ${{ github.ref_name == 'master' && job.status == 'success' }} shell: bash run: | # Save the private key to a file @@ -49,3 +50,9 @@ jobs: # Run the build script ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_ID $GITHUB_SHA + + - name: Notify Discord + uses: Tim203/actions-git-discord-webhook@main + with: + webhook_url: ${{ secrets.DISCORD_WEBHOOK }} + status: ${{ job.status }} From 64cb16b72a08292de92564616421b361b91266d5 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 13 Feb 2023 22:20:47 +0100 Subject: [PATCH 058/113] Temporarily restore Jenkinsfile to give people time to switch --- Jenkinsfile | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..58099d91 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,30 @@ +pipeline { + agent any + tools { + gradle 'Gradle 7' + jdk 'Java 8' + } + options { + buildDiscarder(logRotator(artifactNumToKeepStr: '5')) + } + stages { + stage ('Build') { + steps { + sh 'git submodule update --init --recursive' + rtGradleRun( + usesPlugin: true, + tool: 'Gradle 7', + buildFile: 'build.gradle.kts', + tasks: 'clean build', + ) + } + post { + success { + archiveArtifacts artifacts: '**/build/libs/floodgate-*.jar', + excludes: '**/floodgate-parent-*.jar,**/floodgate-api.jar,**/floodgate-core.jar', + fingerprint: true + } + } + } + } +} \ No newline at end of file From 38442bc7480320e61f71a3925d82173335345c42 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:18:34 -0500 Subject: [PATCH 059/113] Localize floodgate.core.not_linked (#383) * Localize floodgate.core.not_linked * Update languages submodule * not_linked string has changed slightly --------- Co-authored-by: Tim203 --- .../geysermc/floodgate/module/CommonModule.java | 6 ++++-- .../player/FloodgateHandshakeHandler.java | 14 ++++++++++++-- core/src/main/resources/languages | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index ff45c89d..881f3ede 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -69,6 +69,7 @@ import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.HttpClient; +import org.geysermc.floodgate.util.LanguageManager; @RequiredArgsConstructor public class CommonModule extends AbstractModule { @@ -165,10 +166,11 @@ public FloodgateHandshakeHandler handshakeHandler( FloodgateConfig config, SkinUploadManager skinUploadManager, @Named("playerAttribute") AttributeKey playerAttribute, - FloodgateLogger logger) { + FloodgateLogger logger, + LanguageManager languageManager) { return new FloodgateHandshakeHandler(handshakeHandlers, api, cipher, config, - skinUploadManager, playerAttribute, logger); + skinUploadManager, playerAttribute, logger, languageManager); } @Provides diff --git a/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java b/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java index c0a1e242..b84ff1ba 100644 --- a/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/player/FloodgateHandshakeHandler.java @@ -52,7 +52,9 @@ import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.util.BedrockData; +import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.InvalidFormatException; +import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.LinkedPlayer; import org.geysermc.floodgate.util.Utils; @@ -64,6 +66,7 @@ public final class FloodgateHandshakeHandler { private final SkinUploadManager skinUploadManager; private final AttributeKey playerAttribute; private final FloodgateLogger logger; + private final LanguageManager languageManager; public FloodgateHandshakeHandler( HandshakeHandlersImpl handshakeHandlers, @@ -72,7 +75,8 @@ public FloodgateHandshakeHandler( FloodgateConfig config, SkinUploadManager skinUploadManager, AttributeKey playerAttribute, - FloodgateLogger logger) { + FloodgateLogger logger, + LanguageManager languageManager) { this.handshakeHandlers = handshakeHandlers; this.api = api; @@ -81,6 +85,7 @@ public FloodgateHandshakeHandler( this.skinUploadManager = skinUploadManager; this.playerAttribute = playerAttribute; this.logger = logger; + this.languageManager = languageManager; } /** @@ -211,7 +216,12 @@ private HandshakeResult handlePart2( linkedPlayer != null ? linkedPlayer.clone() : null, hostname); if (config.getPlayerLink().isRequireLink() && linkedPlayer == null) { - handshakeData.setDisconnectReason("floodgate.core.not_linked"); + String reason = languageManager.getString( + "floodgate.core.not_linked", + bedrockData.getLanguageCode(), + Constants.LINK_INFO_URL + ); + handshakeData.setDisconnectReason(reason); } handshakeHandlers.callHandshakeHandlers(handshakeData); diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 38cb4a52..204f4fe4 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 38cb4a52df713cb0bc1738370aa8135c01f0cabc +Subproject commit 204f4fe4920defac3a472e762d95233d0756f35f From 82d27bedc89627b256a42773ab255b35a46eb63d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 14 Feb 2023 00:38:43 +0100 Subject: [PATCH 060/113] Update bstats dependency --- build-logic/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index b316fcd5..7fa0c6d3 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -34,7 +34,7 @@ object Versions { const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" const val cloudVersion = "1.5.0" - const val bstatsVersion = "3.0.0" + const val bstatsVersion = "3.0.1" const val javaWebsocketVersion = "1.5.2" From cfd28e8feb7e90161cb905ba6746c50ba3e96b14 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 18 Feb 2023 04:46:44 -0500 Subject: [PATCH 061/113] Only publish and notify Discord on push if running inside this repository (#387) * Only attempt publishing if running in GeyserMC/Floodgate * Also restrict the discord notification --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 40edc4fd..b67afb27 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: arguments: build - name: Publish to Maven Repository - if: ${{ job.status == 'success' }} + if: ${{ job.status == 'success' && github.repository == 'GeyserMC/Floodgate' }} uses: gradle/gradle-build-action@v2 env: ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} @@ -32,7 +32,7 @@ jobs: arguments: publish - name: Publish to Downloads API - if: ${{ github.ref_name == 'master' && job.status == 'success' }} + if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Floodgate' }} shell: bash run: | # Save the private key to a file @@ -52,6 +52,7 @@ jobs: ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_ID $GITHUB_SHA - name: Notify Discord + if: ${{ github.repository == 'GeyserMC/Floodgate' }} uses: Tim203/actions-git-discord-webhook@main with: webhook_url: ${{ secrets.DISCORD_WEBHOOK }} From dd37174ad3e89b3da21e3599b28bfe1cc3b4dd17 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 18 Feb 2023 04:57:21 -0500 Subject: [PATCH 062/113] Fix injection of LanguageManager/Slf4jFloodgate on Velocity (circular proxy) (#388) --- .../org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java b/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java index f439d180..17efe8a6 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java +++ b/velocity/src/main/java/org/geysermc/floodgate/logger/Slf4jFloodgateLogger.java @@ -39,10 +39,11 @@ @Singleton public final class Slf4jFloodgateLogger implements FloodgateLogger { @Inject private Logger logger; - @Inject private LanguageManager languageManager; + private LanguageManager languageManager; @Inject - private void init(FloodgateConfig config) { + private void init(LanguageManager languageManager, FloodgateConfig config) { + this.languageManager = languageManager; if (config.isDebug() && !logger.isDebugEnabled()) { Configurator.setLevel(logger.getName(), Level.DEBUG); } From 846b60627f75ed2a86e1534e85bfea7100001bde Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 26 Feb 2023 01:12:18 +0100 Subject: [PATCH 063/113] Made various changes to the build action --- .github/workflows/build.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b67afb27..016d0bfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,25 +15,30 @@ jobs: with: java-version: 8 distribution: temurin - cache: gradle - name: Build uses: gradle/gradle-build-action@v2 with: arguments: build + cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }} - name: Publish to Maven Repository - if: ${{ job.status == 'success' && github.repository == 'GeyserMC/Floodgate' }} + if: ${{ github.repository == 'GeyserMC/Floodgate' }} uses: gradle/gradle-build-action@v2 env: ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} with: arguments: publish + cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }} - name: Publish to Downloads API - if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Floodgate' }} + if: ${{ github.ref_name == 'master' && github.repository == 'GeyserMC/Floodgate' }} shell: bash + env: + DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} + DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} + DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} run: | # Save the private key to a file echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa @@ -49,11 +54,10 @@ jobs: ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ~/files/floodgate-parent-*.jar ~/files/floodgate-api.jar ~/files/floodgate-core.jar # Run the build script - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_ID $GITHUB_SHA + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_NUMBER $GITHUB_SHA - name: Notify Discord - if: ${{ github.repository == 'GeyserMC/Floodgate' }} + if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Floodgate' }} uses: Tim203/actions-git-discord-webhook@main with: webhook_url: ${{ secrets.DISCORD_WEBHOOK }} - status: ${{ job.status }} From e4a20802990c82f2711250f617d17d3c7a9660f3 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 26 Feb 2023 01:18:34 +0100 Subject: [PATCH 064/113] Update maven deploy location --- .../src/main/kotlin/floodgate.publish-conventions.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts index 39e180ae..0f7b7618 100644 --- a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts @@ -10,6 +10,6 @@ indra { } } - publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/artifactory/maven-snapshots") - publishReleasesTo("geysermc", "https://repo.opencollab.dev/artifactory/maven-releases") + publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots") + publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases") } \ No newline at end of file From 9512528b352f3ed8cbca19f94bb4670c95851c1c Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 27 Feb 2023 00:40:36 +0100 Subject: [PATCH 065/113] Relocate MySQL database extension dependencies --- database/mysql/build.gradle.kts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/database/mysql/build.gradle.kts b/database/mysql/build.gradle.kts index 3b6f25a3..3975a2e0 100644 --- a/database/mysql/build.gradle.kts +++ b/database/mysql/build.gradle.kts @@ -1,12 +1,17 @@ -val mysqlClientVersion = "8.0.30" -val hikariVersion = "4.0.3" - dependencies { - provided(projects.core) - implementation("mysql", "mysql-connector-java", mysqlClientVersion) - implementation("com.zaxxer", "HikariCP", hikariVersion) + provided(projects.core) + + // update HikariCP when we move to Java 11+ + implementation("com.zaxxer", "HikariCP", "4.0.3") + + implementation("com.mysql", "mysql-connector-j", "8.0.32") { + exclude("com.google.protobuf", "protobuf-java") + } } description = "The Floodgate database extension for MySQL" -relocate("org.mariadb") +// relocate everything from mysql-connector-j and HikariCP +relocate("com.mysql") +relocate("com.zaxxer.hikari") +relocate("org.slf4j") From 2230f2a6d3b01f2547933d3caa4626678ad5c602 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 26 Feb 2023 18:48:49 -0500 Subject: [PATCH 066/113] Shutdown metrics on platform shutdown (#386) * Shutdown metrics on platorm shutdown * Listen to event instead of hardcoding it * Annotate Metrics as a Listener * Use temporary bStats fork to properly shutdown bStats * Use bstats-base dependency (instead of the whole project I guess?) * Formatting change --------- Co-authored-by: Tim203 --- build-logic/src/main/kotlin/Versions.kt | 2 +- core/build.gradle.kts | 4 +++- .../main/java/org/geysermc/floodgate/util/Metrics.java | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 7fa0c6d3..b501b9e2 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -34,7 +34,7 @@ object Versions { const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" const val cloudVersion = "1.5.0" - const val bstatsVersion = "3.0.1" + const val bstatsVersion = "d2fbbd6823" const val javaWebsocketVersion = "1.5.2" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d7d48737..46b43de2 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -15,7 +15,9 @@ dependencies { api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion) api("cloud.commandframework", "cloud-core", Versions.cloudVersion) api("org.yaml", "snakeyaml", Versions.snakeyamlVersion) - api("org.bstats", "bstats-base", Versions.bstatsVersion) + + //todo use official dependency once https://github.com/Bastian/bstats-metrics/pull/118 is merged + api("com.github.Konicai.bstats-metrics", "bstats-base", Versions.bstatsVersion) } // present on all platforms diff --git a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java index 4ef585b7..7e388940 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Metrics.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Metrics.java @@ -38,12 +38,16 @@ import org.bstats.charts.SimplePie; import org.bstats.charts.SingleLineChart; import org.bstats.json.JsonObjectBuilder; +import org.geysermc.event.Listener; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig.MetricsConfig; +import org.geysermc.floodgate.event.lifecycle.ShutdownEvent; import org.geysermc.floodgate.platform.util.PlatformUtils; +@Listener @AutoBind public final class Metrics { private final MetricsBase metricsBase; @@ -145,4 +149,9 @@ private void appendPlatformData(JsonObjectBuilder builder) { builder.appendField("osVersion", System.getProperty("os.version")); builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); } + + @Subscribe + public void onShutdown(ShutdownEvent ignored) { + metricsBase.shutdown(); + } } From d572ec97fd6dbb4187a4cd8b89712029d4127a90 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 1 Mar 2023 13:33:22 +0100 Subject: [PATCH 067/113] Store forms in a synchronized map --- .../geysermc/floodgate/pluginmessage/channel/FormChannel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java index b12ec325..1da89bc1 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java @@ -28,6 +28,7 @@ import com.google.common.base.Charsets; import com.google.inject.Inject; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; @@ -41,7 +42,8 @@ public class FormChannel implements PluginMessageChannel { private final FormDefinitions formDefinitions = FormDefinitions.instance(); - private final Short2ObjectMap storedForms = new Short2ObjectOpenHashMap<>(); + private final Short2ObjectMap storedForms = + Short2ObjectMaps.synchronize(new Short2ObjectOpenHashMap<>()); private final AtomicInteger nextFormId = new AtomicInteger(0); @Inject private PluginMessageUtils pluginMessageUtils; From 8b002e2b9f3cb780e19f3d6034bbecc00e678047 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 1 Mar 2023 20:23:28 +0100 Subject: [PATCH 068/113] Attempt to fix publishing to the Downloads API --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 016d0bfd..f171fdbe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,7 +51,7 @@ jobs: scp -B -o StrictHostKeyChecking=no -i id_ecdsa **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/ # Remove un-needed artifacts - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ~/files/floodgate-parent-*.jar ~/files/floodgate-api.jar ~/files/floodgate-core.jar + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./files/floodgate-parent-*.jar ./files/floodgate-api.jar ./files/floodgate-core.jar # Run the build script ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_NUMBER $GITHUB_SHA From 089b9a7e90c0771e5fddb0fddcb794455b20e1bb Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 1 Mar 2023 20:27:12 +0100 Subject: [PATCH 069/113] Another attempt --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f171fdbe..b580f4c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,7 +51,7 @@ jobs: scp -B -o StrictHostKeyChecking=no -i id_ecdsa **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/ # Remove un-needed artifacts - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./files/floodgate-parent-*.jar ./files/floodgate-api.jar ./files/floodgate-core.jar + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./files/floodgate-api.jar ./files/floodgate-core.jar # Run the build script ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_NUMBER $GITHUB_SHA From 65e4de4e7a63984b5a6bbd0f422599746c9d9224 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 19 Mar 2023 17:12:31 +0000 Subject: [PATCH 070/113] Update downloads api publishing steps --- .github/workflows/build.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b580f4c4..bf63cb0b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,18 +43,25 @@ jobs: # Save the private key to a file echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa chmod 600 id_ecdsa + + # Set the project + project=floodgate # Get the version from gradle.properties version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + + # Create the build folder + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/" # Copy over artifacts - scp -B -o StrictHostKeyChecking=no -i id_ecdsa **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ # Remove un-needed artifacts - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./files/floodgate-api.jar ./files/floodgate-core.jar + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./uploads/$project/$GITHUB_RUN_NUMBER/floodgate-api.jar ./uploads/$project/$GITHUB_RUN_NUMBER/floodgate-core.jar - # Run the build script - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_NUMBER $GITHUB_SHA + # Push the metadata + echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ - name: Notify Discord if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Floodgate' }} From f0a20aa967007bf2b60528d3522b0c21379e445d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 28 Mar 2023 14:41:41 +0200 Subject: [PATCH 071/113] Support changes introduced in a recent BungeeCord commit --- bungee/build.gradle.kts | 2 +- .../inject/bungee/BungeeInjector.java | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index 316e91ed..f0e93a8a 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -1,4 +1,4 @@ -var bungeeCommit = "ff5727c" +var bungeeCommit = "dfd847f" var gsonVersion = "2.8.0" var guavaVersion = "21.0" diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index e6a3e964..ac39d4d0 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -35,6 +35,7 @@ import lombok.RequiredArgsConstructor; import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.protocol.MinecraftEncoder; +import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender; import net.md_5.bungee.protocol.Varint21LengthFieldPrepender; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.inject.CommonPlatformInjector; @@ -52,6 +53,16 @@ public final class BungeeInjector extends CommonPlatformInjector { public void inject() { // Can everyone just switch to Velocity please :) + // Newer Bungee versions have a separate prepender for backend and client connections + Field serverFramePrepender = + ReflectionUtils.getField(PipelineUtils.class, "serverFramePrepender"); + if (serverFramePrepender != null) { + BungeeCustomServerPrepender customServerPrepender = new BungeeCustomServerPrepender( + this, ReflectionUtils.castedStaticValue(serverFramePrepender) + ); + BungeeReflectionUtils.setFieldValue(null, serverFramePrepender, customServerPrepender); + } + Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); // Required in order to inject into both Geyser <-> proxy AND proxy <-> server @@ -119,6 +130,22 @@ BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector) } } + @RequiredArgsConstructor + private static final class BungeeCustomServerPrepender + extends Varint21LengthFieldExtraBufPrepender { + private final BungeeInjector injector; + private final Varint21LengthFieldExtraBufPrepender original; + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + original.handlerAdded(ctx); + // The Minecraft encoder being in the pipeline isn't present until later + + // Proxy <-> Server + ctx.pipeline().addLast(BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector)); + } + } + @RequiredArgsConstructor private static final class BungeeClientToProxyInjectInitializer extends ChannelInboundHandlerAdapter { From 3c0e30bff78a73a547017957732f3f1438f3b369 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 31 Mar 2023 13:14:37 -0400 Subject: [PATCH 072/113] Folia support Co-Authored-By: Camotoy <20743703+Camotoy@users.noreply.github.com> --- build-logic/src/main/kotlin/Versions.kt | 2 +- settings.gradle.kts | 10 +--- spigot/build.gradle.kts | 15 +++++- .../module/SpigotPlatformModule.java | 2 +- .../pluginmessage/SpigotSkinApplier.java | 11 ++-- .../geysermc/floodgate/util/ClassNames.java | 6 +++ .../floodgate/util/SpigotCommandUtil.java | 10 ++-- .../util/SpigotVersionSpecificMethods.java | 53 ++++++++++++++----- spigot/src/main/resources/plugin.yml | 3 +- 9 files changed, 73 insertions(+), 39 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index b501b9e2..a7d5d0ff 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -28,7 +28,7 @@ object Versions { const val cumulusVersion = "1.1.1" const val eventsVersion = "1.0-SNAPSHOT" const val configUtilsVersion = "1.0-SNAPSHOT" - const val spigotVersion = "1.13-R0.1-SNAPSHOT" + const val spigotVersion = "1.19.4-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" const val guiceVersion = "5.1.0" const val nettyVersion = "4.1.49.Final" diff --git a/settings.gradle.kts b/settings.gradle.kts index 30992cbc..eee1e4e4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,7 +4,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { -// mavenLocal() + mavenLocal() // Geyser, Cumulus etc. maven("https://repo.opencollab.dev/maven-releases") { @@ -21,13 +21,7 @@ dependencyResolutionManagement { // maven("https://repo.papermc.io/repository/maven-snapshots") { // mavenContent { snapshotsOnly() } // } - maven("https://repo.papermc.io/repository/maven-public") { - content { - includeGroupByRegex( - "(io\\.papermc\\..*|com\\.destroystokyo\\..*|com\\.velocitypowered)" - ) - } - } + maven("https://repo.papermc.io/repository/maven-public") // Spigot maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") { mavenContent { snapshotsOnly() } diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index 8bd8b9c0..2a819ac0 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -2,12 +2,26 @@ var authlibVersion = "1.5.21" var guavaVersion = "21.0" var gsonVersion = "2.8.5" +indra { + javaVersions { + // For Folia + target(8) + minimumToolchain(17) + } +} + dependencies { api(projects.core) implementation("cloud.commandframework", "cloud-bukkit", Versions.cloudVersion) // hack to make pre 1.12 work implementation("com.google.guava", "guava", guavaVersion) + + compileOnlyApi("dev.folia", "folia-api", Versions.spigotVersion) { + attributes { + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) + } + } } relocate("com.google.inject") @@ -21,7 +35,6 @@ relocate("com.google.guava") relocate("it.unimi") // these dependencies are already present on the platform -provided("com.destroystokyo.paper", "paper-api", Versions.spigotVersion) provided("com.mojang", "authlib", authlibVersion) provided("io.netty", "netty-transport", Versions.nettyVersion) provided("io.netty", "netty-codec", Versions.nettyVersion) diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java index 0649280e..1c03dc95 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotPlatformModule.java @@ -86,7 +86,7 @@ public CommandUtil commandUtil( SpigotVersionSpecificMethods versionSpecificMethods, LanguageManager languageManager) { return new SpigotCommandUtil( - languageManager, plugin.getServer(), api, versionSpecificMethods, plugin); + languageManager, plugin.getServer(), api, versionSpecificMethods); } @Provides diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index fa599f40..4caa6f00 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -33,7 +33,6 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.floodgate.SpigotPlugin; import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -48,7 +47,6 @@ @Singleton public final class SpigotSkinApplier implements SkinApplier { @Inject private SpigotVersionSpecificMethods versionSpecificMethods; - @Inject private SpigotPlugin plugin; @Inject private EventBus eventBus; @Override @@ -62,8 +60,7 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool // player is probably not logged in yet if (player == null) { if (firstTry) { - Bukkit.getScheduler().runTaskLater( - plugin, + versionSpecificMethods.schedule( () -> applySkin0(floodgatePlayer, skinData, false), 10 * 20 ); @@ -94,12 +91,10 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool replaceSkin(properties, event.newSkin()); - // By running as a task, we don't run into async issues - plugin.getServer().getScheduler().runTask(plugin, () -> { + versionSpecificMethods.maybeSchedule(() -> { for (Player p : Bukkit.getOnlinePlayers()) { if (!p.equals(player) && p.canSee(player)) { - versionSpecificMethods.hidePlayer(p, player); - versionSpecificMethods.showPlayer(p, player); + versionSpecificMethods.hideAndShowPlayer(p, player); } } }); diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 1ca5105a..d4ec2b16 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -78,6 +78,8 @@ public class ClassNames { public static final Field BUNGEE; + public static final boolean IS_FOLIA; + static { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; SPIGOT_MAPPING_PREFIX = "net.minecraft.server." + version; @@ -223,6 +225,10 @@ public class ClassNames { PAPER_VELOCITY_SUPPORT = null; } } + + IS_FOLIA = ReflectionUtils.getClass( + "io.papermc.paper.threadedregions.scheduler.EntityScheduler" + ) != null; } private static T checkNotNull(@CheckForNull T toCheck, @CheckForNull String objectName) { diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java index da3d65bc..4950309d 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java @@ -27,11 +27,9 @@ import java.util.Collection; import java.util.UUID; -import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.platform.command.CommandUtil; @@ -42,19 +40,17 @@ public final class SpigotCommandUtil extends CommandUtil { private final Server server; private final SpigotVersionSpecificMethods versionSpecificMethods; - private final JavaPlugin plugin; private UserAudience console; public SpigotCommandUtil( LanguageManager manager, Server server, FloodgateApi api, - SpigotVersionSpecificMethods versionSpecificMethods, - JavaPlugin plugin) { + SpigotVersionSpecificMethods versionSpecificMethods + ) { super(manager, api); this.server = server; this.versionSpecificMethods = versionSpecificMethods; - this.plugin = plugin; } @Override @@ -120,7 +116,7 @@ public void sendMessage(Object target, String message) { public void kickPlayer(Object player, String message) { // can also be console if (player instanceof Player) { - Bukkit.getScheduler().runTask(plugin, () -> ((Player) player).kickPlayer(message)); + versionSpecificMethods.schedule(() -> ((Player) player).kickPlayer(message), 0); } } diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java index f8e67616..e0dfcb2d 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java @@ -25,16 +25,21 @@ package org.geysermc.floodgate.util; +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.geysermc.floodgate.SpigotPlugin; public final class SpigotVersionSpecificMethods { - private static final boolean NEW_GET_LOCALE; + private static final Method GET_SPIGOT; + private static final Method OLD_GET_LOCALE; private static final boolean NEW_VISIBILITY; static { - NEW_GET_LOCALE = ReflectionUtils.getMethod(Player.class, "getLocale") != null; + GET_SPIGOT = ReflectionUtils.getMethod(Player.class, "spigot"); + OLD_GET_LOCALE = ReflectionUtils.getMethod(Player.Spigot.class, "getLocale"); + NEW_VISIBILITY = null != ReflectionUtils.getMethod( Player.class, "hidePlayer", Plugin.class, Player.class @@ -48,27 +53,51 @@ public SpigotVersionSpecificMethods(SpigotPlugin plugin) { } public String getLocale(Player player) { - if (NEW_GET_LOCALE) { + if (OLD_GET_LOCALE == null) { return player.getLocale(); } - return player.spigot().getLocale(); + Object spigot = ReflectionUtils.invoke(player, GET_SPIGOT); + return ReflectionUtils.castedInvoke(spigot, OLD_GET_LOCALE); } - @SuppressWarnings("deprecation") - public void hidePlayer(Player hideFor, Player playerToHide) { - if (NEW_VISIBILITY) { - hideFor.hidePlayer(plugin, playerToHide); + public void hideAndShowPlayer(Player on, Player target) { + // In Folia we don't have to schedule this as there is no concept of a single main thread. + // Instead, we have to schedule the task per player. + if (ClassNames.IS_FOLIA) { + on.getScheduler().execute(plugin, () -> hideAndShowPlayer0(on, target), null, 0); return; } - hideFor.hidePlayer(playerToHide); + hideAndShowPlayer0(on, target); + } + + public void schedule(Runnable runnable, long delay) { + if (ClassNames.IS_FOLIA) { + plugin.getServer().getAsyncScheduler().runDelayed( + plugin, $ -> runnable.run(), delay * 50, TimeUnit.MILLISECONDS + ); + return; + } + plugin.getServer().getScheduler().runTaskLater(plugin, runnable, delay); } @SuppressWarnings("deprecation") - public void showPlayer(Player showFor, Player playerToShow) { + private void hideAndShowPlayer0(Player source, Player target) { if (NEW_VISIBILITY) { - showFor.showPlayer(plugin, playerToShow); + source.hidePlayer(plugin, target); + source.showPlayer(plugin, target); + return; + } + source.hidePlayer(target); + source.showPlayer(target); + } + + public void maybeSchedule(Runnable runnable) { + // In Folia we don't have to schedule this as there is no concept of a single main thread. + // Instead, we have to schedule the task per player. + if (ClassNames.IS_FOLIA) { + runnable.run(); return; } - showFor.showPlayer(playerToShow); + plugin.getServer().getScheduler().runTask(plugin, runnable); } } diff --git a/spigot/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml index c9a5d232..0c9fe9f1 100644 --- a/spigot/src/main/resources/plugin.yml +++ b/spigot/src/main/resources/plugin.yml @@ -4,4 +4,5 @@ version: ${version} author: ${author} website: ${url} main: org.geysermc.floodgate.SpigotPlugin -api-version: 1.13 \ No newline at end of file +api-version: 1.13 +folia-supported: true \ No newline at end of file From 104cbdd51bf511a152395d212c6ceb4eda12c1d9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 31 Mar 2023 13:28:18 -0400 Subject: [PATCH 073/113] Use Java 17 to compile --- .github/workflows/build.yml | 2 +- .github/workflows/pullrequest.yml | 4 ++-- Jenkinsfile | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf63cb0b..a53a65eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/setup-java@v3 with: - java-version: 8 + java-version: 17 distribution: temurin - name: Build diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 4edc17e3..016ad98d 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -10,11 +10,11 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 1.8 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '8' + java-version: '17' cache: 'gradle' - name: Build with Maven diff --git a/Jenkinsfile b/Jenkinsfile index 58099d91..f9dbc474 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,7 @@ pipeline { agent any tools { gradle 'Gradle 7' - jdk 'Java 8' + jdk 'Java 17' } options { buildDiscarder(logRotator(artifactNumToKeepStr: '5')) From 2702bc3e832318c8fdcb4d73416151ce36968eed Mon Sep 17 00:00:00 2001 From: byteful <80184082+byteful@users.noreply.github.com> Date: Fri, 31 Mar 2023 15:44:17 -0500 Subject: [PATCH 074/113] Check IS_FOLIA silently (#400) --- .../src/main/java/org/geysermc/floodgate/util/ClassNames.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index d4ec2b16..364eb7e7 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -226,7 +226,7 @@ public class ClassNames { } } - IS_FOLIA = ReflectionUtils.getClass( + IS_FOLIA = ReflectionUtils.getClassSilently( "io.papermc.paper.threadedregions.scheduler.EntityScheduler" ) != null; } From 1b9042eacff109e020b9fe3cc93af60f16a48afb Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 9 May 2023 23:42:53 -0400 Subject: [PATCH 075/113] Bump bungeecord-proxy commit version (#409) --- bungee/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index f0e93a8a..30a98353 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -1,4 +1,4 @@ -var bungeeCommit = "dfd847f" +var bungeeCommit = "9e5ed82" var gsonVersion = "2.8.0" var guavaVersion = "21.0" From 202a30aae67196fc797600b4f57544b0265b87e4 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 27 May 2023 13:40:58 +0200 Subject: [PATCH 076/113] Fixed GitHub Action run numbers and updated download url --- build-logic/src/main/kotlin/extensions.kt | 10 ++++-- .../command/main/VersionSubcommand.java | 36 ++++++++++++------- .../geysermc/floodgate/news/NewsChecker.java | 4 +-- .../geysermc/floodgate/util/Constants.java | 8 +++-- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index cbb5e8a8..bbf7531c 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -40,7 +40,7 @@ fun Project.lastCommitHash(): String? = the().commit()?.name?.substring(0, 7) fun Project.branchName(): String = - the().branchName() ?: System.getenv("BRANCH_NAME") ?: "local/dev" + the().branchName() ?: jenkinsBranchName() ?: "local/dev" fun Project.shouldAddBranchName(): Boolean = System.getenv("IGNORE_BRANCH")?.toBoolean() ?: (branchName() !in arrayOf("master", "local/dev")) @@ -49,7 +49,7 @@ fun Project.versionWithBranchName(): String = branchName().replace(Regex("[^0-9A-Za-z-_]"), "-") + '-' + version fun buildNumber(): Int = - System.getenv("BUILD_NUMBER")?.let { Integer.parseInt(it) } ?: -1 + (System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1 fun buildNumberAsString(): String = buildNumber().takeIf { it != -1 }?.toString() ?: "??" @@ -78,4 +78,8 @@ fun Project.relocate(pattern: String) = .add(pattern) private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String = - if (excludedOn and bit > 0) section else "" \ No newline at end of file + if (excludedOn and bit > 0) section else "" + +// todo remove these when we're not using Jenkins anymore +private fun jenkinsBranchName(): String? = System.getenv("BRANCH_NAME") +private fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER") \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java index ea985778..985c47c1 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java @@ -28,8 +28,9 @@ import static org.geysermc.floodgate.util.Constants.COLOR_CHAR; import cloud.commandframework.context.CommandContext; -import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.inject.Inject; +import com.google.inject.name.Named; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.command.WhitelistCommand.Message; import org.geysermc.floodgate.command.util.Permission; @@ -45,6 +46,10 @@ public class VersionSubcommand extends FloodgateSubCommand { @Inject private FloodgateLogger logger; + @Inject + @Named("implementationName") + private String implementationName; + @Override public String name() { return "version"; @@ -70,14 +75,19 @@ public void execute(CommandContext context) { Constants.VERSION, Constants.GIT_BRANCH )); - String baseUrl = String.format( - "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/", - Constants.GIT_BRANCH - ); + //noinspection ConstantValue + if (!Constants.GIT_MAIN_BRANCH.equals(Constants.GIT_BRANCH)) { + sender.sendMessage(String.format( + COLOR_CHAR + "7Detected that you aren't on the %s branch, " + + "so we can't fetch the latest version.", + Constants.GIT_MAIN_BRANCH + )); + return; + } httpClient.asyncGet( - baseUrl + "buildNumber", - JsonElement.class + String.format(Constants.LATEST_VERSION_URL, Constants.PROJECT_NAME), + JsonObject.class ).whenComplete((result, error) -> { if (error != null) { sender.sendMessage(COLOR_CHAR + "cCould not retrieve latest version info!"); @@ -85,10 +95,9 @@ public void execute(CommandContext context) { return; } - JsonElement response = result.getResponse(); + JsonObject response = result.getResponse(); - logger.info(String.valueOf(response)); - logger.info("{}", result.getHttpCode()); + logger.debug("code: {}, response: ", result.getHttpCode(), String.valueOf(response)); if (result.getHttpCode() == 404) { sender.sendMessage( @@ -102,20 +111,21 @@ public void execute(CommandContext context) { //todo make it more generic instead of using a Whitelist command strings logger.error( "Got an error from requesting the latest Floodgate version: {}", - response.toString() + String.valueOf(response) ); sender.sendMessage(Message.UNEXPECTED_ERROR); return; } - int buildNumber = response.getAsInt(); + int buildNumber = response.get("build").getAsInt(); if (buildNumber > Constants.BUILD_NUMBER) { sender.sendMessage(String.format( COLOR_CHAR + "7There is a newer version of Floodgate available!\n" + COLOR_CHAR + "7You are " + COLOR_CHAR + "e%s " + COLOR_CHAR + "7builds behind.\n" + COLOR_CHAR + "7Download the latest Floodgate version here: " + COLOR_CHAR + "b%s", - buildNumber - Constants.BUILD_NUMBER, baseUrl + buildNumber - Constants.BUILD_NUMBER, + String.format(Constants.LATEST_DOWNLOAD_URL, implementationName) )); return; } diff --git a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java index 40358247..71f9d667 100644 --- a/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java +++ b/core/src/main/java/org/geysermc/floodgate/news/NewsChecker.java @@ -81,7 +81,7 @@ private void schedule(long delayMs) { private void checkNews() { HttpResponse response = httpClient.getSilent( - Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME, + Constants.NEWS_OVERVIEW_URL + Constants.PROJECT_NAME, JsonArray.class ); @@ -173,7 +173,7 @@ public void addNews(NewsItem item) { switch (item.getType()) { case ANNOUNCEMENT: - if (!item.getDataAs(AnnouncementData.class).isAffected(Constants.NEWS_PROJECT_NAME)) { + if (!item.getDataAs(AnnouncementData.class).isAffected(Constants.PROJECT_NAME)) { return; } break; diff --git a/core/src/main/templates/org/geysermc/floodgate/util/Constants.java b/core/src/main/templates/org/geysermc/floodgate/util/Constants.java index b79a610f..62cec467 100644 --- a/core/src/main/templates/org/geysermc/floodgate/util/Constants.java +++ b/core/src/main/templates/org/geysermc/floodgate/util/Constants.java @@ -29,6 +29,7 @@ public final class Constants { public static final String VERSION = "@floodgateVersion@"; public static final int BUILD_NUMBER = Integer.parseInt("@buildNumber@"); public static final String GIT_BRANCH = "@branch@"; + public static final String GIT_MAIN_BRANCH = "master"; public static final int METRICS_ID = 14649; public static final char COLOR_CHAR = '\u00A7'; @@ -48,9 +49,12 @@ public final class Constants { public static final String NEWS_OVERVIEW_URL = "http" + API_BASE_URL + "/v2/news/"; public static final String GET_BEDROCK_LINK = "http" + API_BASE_URL + "/v2/link/bedrock/"; + public static final String PROJECT_NAME = "floodgate"; public static final String LINK_INFO_URL = "https://link.geysermc.org/"; - - public static final String NEWS_PROJECT_NAME = "floodgate"; + public static final String LATEST_DOWNLOAD_URL = + "https://geysermc.org/download#%s"; + public static final String LATEST_VERSION_URL = + "https://download.geysermc.org/v2/projects/%s/versions/latest/builds/latest"; public static final String NTP_SERVER = "time.cloudflare.com"; From e23f1b2659b405162f8e73a5e3c635c044f2a2a9 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 27 May 2023 14:16:08 +0200 Subject: [PATCH 077/113] Jitpack why... --- bungee/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index 30a98353..14683854 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -1,4 +1,4 @@ -var bungeeCommit = "9e5ed82" +var bungeeCommit = "master-SNAPSHOT" var gsonVersion = "2.8.0" var guavaVersion = "21.0" From 227858930d98dc8e89054b38edebc3b432c0a5eb Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 9 Jun 2023 18:32:31 +0200 Subject: [PATCH 078/113] Relocate SnakeYAML --- bungee/build.gradle.kts | 3 ++- core/build.gradle.kts | 1 - spigot/build.gradle.kts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index 14683854..b438a04e 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -12,9 +12,10 @@ relocate("net.kyori") relocate("cloud.commandframework") // used in cloud relocate("io.leangen.geantyref") +// since 1.20 +relocate("org.yaml") // these dependencies are already present on the platform provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", bungeeCommit) provided("com.google.code.gson", "gson", gsonVersion) provided("com.google.guava", "guava", guavaVersion) -provided("org.yaml", "snakeyaml", Versions.snakeyamlVersion) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 46b43de2..1df4ae95 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -14,7 +14,6 @@ dependencies { api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion) api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion) api("cloud.commandframework", "cloud-core", Versions.cloudVersion) - api("org.yaml", "snakeyaml", Versions.snakeyamlVersion) //todo use official dependency once https://github.com/Bastian/bstats-metrics/pull/118 is merged api("com.github.Konicai.bstats-metrics", "bstats-base", Versions.bstatsVersion) diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index 2a819ac0..c0dad7af 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -33,10 +33,11 @@ relocate("com.google.common") relocate("com.google.guava") // hack to make (old versions? of) Paper work relocate("it.unimi") +// since 1.20 +relocate("org.yaml") // these dependencies are already present on the platform provided("com.mojang", "authlib", authlibVersion) provided("io.netty", "netty-transport", Versions.nettyVersion) provided("io.netty", "netty-codec", Versions.nettyVersion) provided("com.google.code.gson", "gson", gsonVersion) -provided("org.yaml", "snakeyaml", Versions.snakeyamlVersion) From d1f3aae56c80abc31fb55cb4e5e98c70e99d3d72 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 14 Aug 2023 01:04:02 +0200 Subject: [PATCH 079/113] Backported Folia detection fix --- .../src/main/java/org/geysermc/floodgate/util/ClassNames.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 364eb7e7..11f757f1 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -227,7 +227,7 @@ public class ClassNames { } IS_FOLIA = ReflectionUtils.getClassSilently( - "io.papermc.paper.threadedregions.scheduler.EntityScheduler" + "io.papermc.paper.threadedregions.RegionizedServer" ) != null; } From 9c79df6fb7f9b5f11380114fe183f53205db77f6 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 15 Aug 2023 19:00:05 +0200 Subject: [PATCH 080/113] Bump Geyser, Cumulus, Events versions to fix an issue with Events --- api/build.gradle.kts | 2 +- build-logic/src/main/kotlin/Versions.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 09fb2163..4418b61a 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { - api("org.geysermc", "common", Versions.geyserVersion) + api("org.geysermc.geyser", "common", Versions.geyserVersion) api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) api("org.geysermc.event", "events", Versions.eventsVersion) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index a7d5d0ff..139a3ef5 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,9 +24,9 @@ */ object Versions { - const val geyserVersion = "2.0.7-SNAPSHOT" - const val cumulusVersion = "1.1.1" - const val eventsVersion = "1.0-SNAPSHOT" + const val geyserVersion = "2.1.2-SNAPSHOT" + const val cumulusVersion = "1.1.2" + const val eventsVersion = "1.1-SNAPSHOT" const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.19.4-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" From 492be77ad94043688c4b7f7a374541566cade65d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 17 Aug 2023 11:35:12 +0200 Subject: [PATCH 081/113] Fixed an error during shutdown --- .../geysermc/floodgate/link/PlayerLinkHolder.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java b/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java index a91ba679..4b140c2f 100644 --- a/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java +++ b/core/src/main/java/org/geysermc/floodgate/link/PlayerLinkHolder.java @@ -71,12 +71,15 @@ public final class PlayerLinkHolder { private URLClassLoader classLoader; private PlayerLink instance; - @NonNull - public PlayerLink load() { + public @NonNull PlayerLink load() { if (instance != null) { return instance; } + instance = load0(); + return instance; + } + private @NonNull PlayerLink load0() { if (config == null) { throw new IllegalStateException("Config cannot be null!"); } @@ -189,7 +192,7 @@ public PlayerLink load() { }); injectorHolder.set(linkInjector); - instance = linkInjector.getInstance(mainClass); + PlayerLink instance = linkInjector.getInstance(mainClass); // we use our own internal PlayerLinking when global linking is enabled if (linkConfig.isEnableGlobalLinking()) { @@ -220,6 +223,8 @@ public PlayerLink load() { @Subscribe public void onShutdown(ShutdownEvent ignored) throws Exception { instance.stop(); - classLoader.close(); + if (classLoader != null) { + classLoader.close(); + } } } From 26c11bdede6761073629c5f3fd90bd0b61e2af33 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:36:02 -0700 Subject: [PATCH 082/113] 1.20.2 Support (#449) * Spigot 1.20.2 Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Oops Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * 1.20.2 velocity (#1) * 1.20.2 Velocity Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Archive build artifacts Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Fix typo in velocity-plugin.json Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Fix formatting and apply codestyle to eclipse Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Ignore changes to core base prefs Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Proper ignore Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Remove buildship prefs Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Formatting Signed-off-by: GitHub * Formatting Signed-off-by: GitHub * Properly build PRs * Formatting + remove artifacts Signed-off-by: GitHub * Throw IllegalStateException Signed-off-by: GitHub --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Signed-off-by: GitHub --- .github/workflows/pullrequest.yml | 5 +- .../addon/data/SpigotDataHandler.java | 46 +++++++--- .../geysermc/floodgate/util/ClassNames.java | 85 +++++++++++++++++-- velocity/build.gradle.kts | 9 +- .../addon/data/VelocityProxyDataHandler.java | 8 +- .../src/main/resources/velocity-plugin.json | 2 +- 6 files changed, 132 insertions(+), 23 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 016ad98d..1ba39fbd 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -8,7 +8,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - name: Checkout repository and submodules + uses: actions/checkout@v3 + with: + submodules: recursive - name: Set up JDK 17 uses: actions/setup-java@v2 diff --git a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java index bc5742db..55dfc36e 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java +++ b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java @@ -31,6 +31,7 @@ import com.mojang.authlib.GameProfile; import io.netty.channel.Channel; import io.netty.util.AttributeKey; +import java.lang.reflect.InvocationTargetException; import java.net.InetSocketAddress; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.config.FloodgateConfig; @@ -57,9 +58,27 @@ protected void setNewIp(Channel channel, InetSocketAddress newIp) { } @Override - protected Object setHostname(Object handshakePacket, String hostname) { - setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname); - return handshakePacket; + protected Object setHostname(Object handshakePacket, String hostname) throws IllegalStateException { + if (ClassNames.IS_PRE_1_20_2) { + // 1.20.1 and below + setValue(handshakePacket, ClassNames.HANDSHAKE_HOST, hostname); + + return handshakePacket; + } else { + // 1.20.2 and above + try { + Object[] components = new Object[]{ + ClassNames.HANDSHAKE_PORT.get(handshakePacket), + hostname, + ClassNames.HANDSHAKE_PROTOCOL.get(handshakePacket), + ClassNames.HANDSHAKE_INTENTION.get(handshakePacket) + }; + + return ClassNames.HANDSHAKE_PACKET_CONSTRUCTOR.newInstance(components); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Failed to create new Handshake packet", e); + } + } } @Override @@ -157,16 +176,23 @@ private boolean checkAndHandleLogin(Object packet) throws Exception { // we have to fake the offline player (login) cycle // just like on Spigot: - // LoginListener#initUUID - // new LoginHandler().fireEvents(); + Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener); - // and the tick of LoginListener will do the rest + if (ClassNames.IS_PRE_1_20_2) { + // 1.20.1 and below - ClassNames.INIT_UUID.invoke(packetListener); + // LoginListener#initUUID + // new LoginHandler().fireEvents(); - Object loginHandler = - ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener); - ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler); + // and the tick of LoginListener will do the rest + + ClassNames.INIT_UUID.invoke(packetListener); + ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler); + } else { + // 1.20.2 and above we directly register the profile + + ClassNames.FIRE_LOGIN_EVENTS_GAME_PROFILE.invoke(loginHandler, gameProfile); + } ctx.pipeline().remove(this); return true; diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 11f757f1..77e00cc7 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -29,11 +29,13 @@ import static org.geysermc.floodgate.util.ReflectionUtils.getBooleanValue; import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallback; import static org.geysermc.floodgate.util.ReflectionUtils.getClassSilently; +import static org.geysermc.floodgate.util.ReflectionUtils.getConstructor; import static org.geysermc.floodgate.util.ReflectionUtils.getField; import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType; import static org.geysermc.floodgate.util.ReflectionUtils.getMethod; import static org.geysermc.floodgate.util.ReflectionUtils.getValue; import static org.geysermc.floodgate.util.ReflectionUtils.invoke; +import static org.geysermc.floodgate.util.ReflectionUtils.makeAccessible; import com.google.common.base.Preconditions; import com.mojang.authlib.GameProfile; @@ -58,27 +60,35 @@ public class ClassNames { public static final Class LOGIN_START_PACKET; public static final Class LOGIN_LISTENER; public static final Class LOGIN_HANDLER; + @Nullable public static final Class CLIENT_INTENT; public static final Constructor CRAFT_OFFLINE_PLAYER_CONSTRUCTOR; public static final Constructor LOGIN_HANDLER_CONSTRUCTOR; + @Nullable public static final Constructor HANDSHAKE_PACKET_CONSTRUCTOR; public static final Field SOCKET_ADDRESS; public static final Field HANDSHAKE_HOST; public static final Field LOGIN_PROFILE; public static final Field PACKET_LISTENER; + @Nullable public static final Field HANDSHAKE_PORT; + @Nullable public static final Field HANDSHAKE_PROTOCOL; + @Nullable public static final Field HANDSHAKE_INTENTION; + @Nullable public static final Field PAPER_DISABLE_USERNAME_VALIDATION; @Nullable public static final BooleanSupplier PAPER_VELOCITY_SUPPORT; public static final Method GET_PROFILE_METHOD; public static final Method LOGIN_DISCONNECT; public static final Method NETWORK_EXCEPTION_CAUGHT; - public static final Method INIT_UUID; - public static final Method FIRE_LOGIN_EVENTS; + @Nullable public static final Method INIT_UUID; + @Nullable public static final Method FIRE_LOGIN_EVENTS; + @Nullable public static final Method FIRE_LOGIN_EVENTS_GAME_PROFILE; public static final Field BUNGEE; public static final boolean IS_FOLIA; + public static final boolean IS_PRE_1_20_2; static { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; @@ -153,14 +163,24 @@ public class ClassNames { ); // there are multiple no-arg void methods + // Pre 1.20.2 uses initUUID so if it's null, we're on 1.20.2 or later INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID"); - checkNotNull(INIT_UUID, "initUUID from LoginListener"); + IS_PRE_1_20_2 = INIT_UUID != null; - Class packetListenerClass = getClassOrFallback( - "net.minecraft.network.PacketListener", - nmsPackage + "PacketListener" - ); - PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass); + if (IS_PRE_1_20_2) { + Class packetListenerClass = getClassOrFallback( + "net.minecraft.network.PacketListener", + nmsPackage + "PacketListener" + ); + + PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass); + } else { + // We get the field by name on 1.20.2+ as there are now multiple fields of this type in network manager + + // PacketListener packetListener of NetworkManager + PACKET_LISTENER = getField(networkManager, "q"); + makeAccessible(PACKET_LISTENER); + } checkNotNull(PACKET_LISTENER, "Packet listener"); LOGIN_HANDLER = getClassOrFallback( @@ -173,8 +193,11 @@ public class ClassNames { checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor"); FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents"); - checkNotNull(FIRE_LOGIN_EVENTS, "fireEvents from LoginHandler"); + // LoginHandler().fireEvents(GameProfile) + FIRE_LOGIN_EVENTS_GAME_PROFILE = getMethod(LOGIN_HANDLER, "fireEvents", GameProfile.class); + checkNotNull(FIRE_LOGIN_EVENTS, FIRE_LOGIN_EVENTS_GAME_PROFILE, + "fireEvents from LoginHandler", "fireEvents(GameProfile) from LoginHandler"); PAPER_DISABLE_USERNAME_VALIDATION = getField(LOGIN_LISTENER, "iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation"); @@ -229,9 +252,53 @@ public class ClassNames { IS_FOLIA = ReflectionUtils.getClassSilently( "io.papermc.paper.threadedregions.RegionizedServer" ) != null; + + if (!IS_PRE_1_20_2) { + // PacketHandshakingInSetProtocol is now a record + // This means its fields are now private and final + // We therefore must use reflection to obtain the constructor + CLIENT_INTENT = getClassOrFallback( + "net.minecraft.network.protocol.handshake.ClientIntent", + nmsPackage + "ClientIntent" + ); + checkNotNull(CLIENT_INTENT, "Client intent enum"); + + HANDSHAKE_PACKET_CONSTRUCTOR = getConstructor(HANDSHAKE_PACKET, false, int.class, + String.class, int.class, CLIENT_INTENT); + checkNotNull(HANDSHAKE_PACKET_CONSTRUCTOR, "Handshake packet constructor"); + + HANDSHAKE_PORT = getField(HANDSHAKE_PACKET, "a"); + checkNotNull(HANDSHAKE_PORT, "Handshake port"); + makeAccessible(HANDSHAKE_PORT); + + HANDSHAKE_PROTOCOL = getField(HANDSHAKE_PACKET, "c"); + checkNotNull(HANDSHAKE_PROTOCOL, "Handshake protocol"); + makeAccessible(HANDSHAKE_PROTOCOL); + + HANDSHAKE_INTENTION = getFieldOfType(HANDSHAKE_PACKET, CLIENT_INTENT); + checkNotNull(HANDSHAKE_INTENTION, "Handshake intention"); + makeAccessible(HANDSHAKE_INTENTION); + } else { + CLIENT_INTENT = null; + HANDSHAKE_PACKET_CONSTRUCTOR = null; + HANDSHAKE_PORT = null; + HANDSHAKE_PROTOCOL = null; + HANDSHAKE_INTENTION = null; + } } private static T checkNotNull(@CheckForNull T toCheck, @CheckForNull String objectName) { return Preconditions.checkNotNull(toCheck, objectName + " cannot be null"); } + + // Ensure one of two is not null + private static T checkNotNull( + @CheckForNull T toCheck, + @CheckForNull T toCheck2, + @CheckForNull String objectName, + @CheckForNull String objectName2 + ) { + return Preconditions.checkNotNull(toCheck != null ? toCheck : toCheck2, + objectName2 + " cannot be null if " + objectName + " is null"); + } } diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 5cd7064a..934ca10c 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -1,8 +1,15 @@ -var velocityVersion = "3.1.1" +var velocityVersion = "3.2.0-SNAPSHOT" var log4jVersion = "2.11.2" var gsonVersion = "2.8.8" var guavaVersion = "25.1-jre" +indra { + javaVersions { + // For Velocity API + target(11) + } +} + dependencies { api(projects.core) implementation("cloud.commandframework", "cloud-velocity", Versions.cloudVersion) diff --git a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java index a623fdaf..b069543e 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java +++ b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java @@ -76,7 +76,13 @@ public final class VelocityProxyDataHandler extends CommonDataHandler { SERVER_LOGIN_PACKET = getPrefixedClass("protocol.packet.ServerLogin"); checkNotNull(SERVER_LOGIN_PACKET, "ServerLogin packet class cannot be null"); - GET_SESSION_HANDLER = getMethodByName(minecraftConnection, "getSessionHandler", true); + + Method sessionHandler = getMethodByName(minecraftConnection, "getSessionHandler", true); + if (sessionHandler == null) { + // We are 1.20.2+ + sessionHandler = getMethodByName(minecraftConnection, "getActiveSessionHandler", true); + } + GET_SESSION_HANDLER = sessionHandler; checkNotNull(GET_SESSION_HANDLER, "getSessionHandler method cannot be null"); INITIAL_LOGIN_SESSION_HANDLER = diff --git a/velocity/src/main/resources/velocity-plugin.json b/velocity/src/main/resources/velocity-plugin.json index a4df39d2..dc7d5e1f 100644 --- a/velocity/src/main/resources/velocity-plugin.json +++ b/velocity/src/main/resources/velocity-plugin.json @@ -1 +1 @@ -{"id": "${id}", "name": "${name}", "version": "${version}", "description": "${description}", "url": "$url}", "authors": ["${author}"], "main": "org.geysermc.floodgate.VelocityPlugin"} \ No newline at end of file +{"id": "${id}", "name": "${name}", "version": "${version}", "description": "${description}", "url": "${url}", "authors": ["${author}"], "main": "org.geysermc.floodgate.VelocityPlugin"} \ No newline at end of file From 7b889180e0664873934fa85c7a2f2ef2d563c960 Mon Sep 17 00:00:00 2001 From: Hidey Boi <62223632+HideyBoi@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:22:20 -0500 Subject: [PATCH 083/113] Fix spigot whitelist command on newer Paper versions (#456) * Jank Fix for #444 * Move Scheduler to WhitelistUtils Also stopped using the Bukkit scheduler and am now scheduling via SpigotVersionSpecificMethods.maybeSchedule * Move setWhitelist to WhitelistUtils Includes requested formatting changes. * switch from runnables to using an lambda expression * Made lambda a single line --------- Co-authored-by: Hidey Boi --- .../floodgate/util/SpigotCommandUtil.java | 5 +++-- .../floodgate/util/WhitelistUtils.java | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java index 4950309d..d6028abe 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotCommandUtil.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.UUID; +import org.bukkit.OfflinePlayer; import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -122,11 +123,11 @@ public void kickPlayer(Object player, String message) { @Override public boolean whitelistPlayer(UUID uuid, String username) { - return WhitelistUtils.addPlayer(uuid, username); + return WhitelistUtils.addPlayer(uuid, username, versionSpecificMethods); } @Override public boolean removePlayerFromWhitelist(UUID uuid, String username) { - return WhitelistUtils.removePlayer(uuid, username); + return WhitelistUtils.removePlayer(uuid, username, versionSpecificMethods); } } diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/WhitelistUtils.java b/spigot/src/main/java/org/geysermc/floodgate/util/WhitelistUtils.java index 6747c28c..d5779565 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/WhitelistUtils.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/WhitelistUtils.java @@ -36,11 +36,12 @@ public final class WhitelistUtils { /** * Whitelist the given Bedrock player. * - * @param uuid the UUID of the Bedrock player to be whitelisted - * @param username the username of the Bedrock player to be whitelisted - * @return true if the player has been whitelisted, false if the player is already whitelisted + * @param uuid the UUID of the Bedrock player to be removed + * @param username the username of the Bedrock player to be removed + * @param versionSpecificMethods a reference to the SpigotVersionSpecificMethods used in SpigotCommandUtil + * @return true if the player has been removed from the whitelist, false if the player wasn't */ - public static boolean addPlayer(UUID uuid, String username) { + public static boolean addPlayer(UUID uuid, String username, SpigotVersionSpecificMethods versionSpecificMethods) { GameProfile profile = new GameProfile(uuid, username); OfflinePlayer player = ReflectionUtils.newInstance( @@ -50,7 +51,7 @@ public static boolean addPlayer(UUID uuid, String username) { if (player.isWhitelisted()) { return false; } - player.setWhitelisted(true); + setWhitelist(player, true, versionSpecificMethods); return true; } @@ -59,10 +60,11 @@ public static boolean addPlayer(UUID uuid, String username) { * * @param uuid the UUID of the Bedrock player to be removed * @param username the username of the Bedrock player to be removed + * @param versionSpecificMethods a reference to the SpigotVersionSpecificMethods used in SpigotCommandUtil * @return true if the player has been removed from the whitelist, false if the player wasn't * whitelisted */ - public static boolean removePlayer(UUID uuid, String username) { + public static boolean removePlayer(UUID uuid, String username, SpigotVersionSpecificMethods versionSpecificMethods) { GameProfile profile = new GameProfile(uuid, username); OfflinePlayer player = ReflectionUtils.newInstance( @@ -72,7 +74,11 @@ public static boolean removePlayer(UUID uuid, String username) { if (!player.isWhitelisted()) { return false; } - player.setWhitelisted(false); + setWhitelist(player, false, versionSpecificMethods); return true; } + + static void setWhitelist(OfflinePlayer player, boolean whitelist, SpigotVersionSpecificMethods versionSpecificMethods) { + versionSpecificMethods.maybeSchedule(() -> player.setWhitelisted(whitelist)); + } } From f9b427fcdf7613f929aff64c493554e2920a0fc6 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:51:34 -0700 Subject: [PATCH 084/113] Maybe fix empty profile issue (#458) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../listener/PaperProfileListener.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java b/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java index 5672ead8..29ade2ec 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java +++ b/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java @@ -26,13 +26,16 @@ package org.geysermc.floodgate.listener; import com.destroystokyo.paper.event.profile.PreFillProfileEvent; +import com.destroystokyo.paper.profile.PlayerProfile; import com.destroystokyo.paper.profile.ProfileProperty; import com.google.inject.Inject; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.player.FloodgatePlayer; @@ -62,4 +65,23 @@ public void onFill(PreFillProfileEvent event) { properties.add(new ProfileProperty("textures", "", "")); event.setProperties(properties); } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player bukkitPlayer = event.getPlayer(); + FloodgatePlayer player = api.getPlayer(bukkitPlayer.getUniqueId()); + if (player == null || player.isLinked()) { + return; + } + + PlayerProfile profile = bukkitPlayer.getPlayerProfile(); + if (profile.getProperties().stream().noneMatch( + prop -> "textures".equals(prop.getName()) && prop.getValue().isEmpty() + && prop.getSignature() != null && prop.getSignature().isEmpty())) { + return; + } + + profile.removeProperty("textures"); + bukkitPlayer.setPlayerProfile(profile); + } } From 71acc6c0f4884952cce1269efc174caec7f635b0 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 13 Oct 2023 17:15:17 +0200 Subject: [PATCH 085/113] Backport a similar fix for 1.20.2 profile properties --- .../pluginmessage/SpigotSkinApplier.java | 12 +------- .../util/SpigotVersionSpecificMethods.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index 4caa6f00..d312afdc 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -39,7 +39,6 @@ import org.geysermc.floodgate.event.EventBus; import org.geysermc.floodgate.event.skin.SkinApplyEventImpl; import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.skin.SkinDataImpl; import org.geysermc.floodgate.util.ClassNames; import org.geysermc.floodgate.util.ReflectionUtils; import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; @@ -78,7 +77,7 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool // MultiMap from Guava. Floodgate relocates Guava. PropertyMap properties = profile.getProperties(); - SkinData currentSkin = currentSkin(properties); + SkinData currentSkin = versionSpecificMethods.currentSkin(properties); SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData); event.setCancelled(floodgatePlayer.isLinked()); @@ -100,15 +99,6 @@ private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, bool }); } - private SkinData currentSkin(PropertyMap properties) { - for (Property texture : properties.get("textures")) { - if (!texture.getValue().isEmpty()) { - return new SkinDataImpl(texture.getValue(), texture.getSignature()); - } - } - return null; - } - private void replaceSkin(PropertyMap properties, SkinData skinData) { properties.removeAll("textures"); Property property = new Property("textures", skinData.value(), skinData.signature()); diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java index e0dfcb2d..7569c615 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/SpigotVersionSpecificMethods.java @@ -25,17 +25,24 @@ package org.geysermc.floodgate.util; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import java.lang.reflect.Method; import java.util.concurrent.TimeUnit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.geysermc.floodgate.SpigotPlugin; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent; +import org.geysermc.floodgate.skin.SkinDataImpl; public final class SpigotVersionSpecificMethods { private static final Method GET_SPIGOT; private static final Method OLD_GET_LOCALE; private static final boolean NEW_VISIBILITY; + private static final Method NEW_PROPERTY_VALUE; + private static final Method NEW_PROPERTY_SIGNATURE; + static { GET_SPIGOT = ReflectionUtils.getMethod(Player.class, "spigot"); OLD_GET_LOCALE = ReflectionUtils.getMethod(Player.Spigot.class, "getLocale"); @@ -44,6 +51,9 @@ public final class SpigotVersionSpecificMethods { Player.class, "hidePlayer", Plugin.class, Player.class ); + + NEW_PROPERTY_VALUE = ReflectionUtils.getMethod(Property.class, "value"); + NEW_PROPERTY_SIGNATURE = ReflectionUtils.getMethod(Property.class, "signature"); } private final SpigotPlugin plugin; @@ -70,6 +80,26 @@ public void hideAndShowPlayer(Player on, Player target) { hideAndShowPlayer0(on, target); } + public SkinApplyEvent.SkinData currentSkin(PropertyMap properties) { + for (Property property : properties.get("textures")) { + String value; + String signature; + if (NEW_PROPERTY_VALUE != null) { + value = ReflectionUtils.castedInvoke(property, NEW_PROPERTY_VALUE); + signature = ReflectionUtils.castedInvoke(property, NEW_PROPERTY_SIGNATURE); + } else { + value = property.getValue(); + signature = property.getSignature(); + } + + //noinspection DataFlowIssue + if (!value.isEmpty()) { + return new SkinDataImpl(value, signature); + } + } + return null; + } + public void schedule(Runnable runnable, long delay) { if (ClassNames.IS_FOLIA) { plugin.getServer().getAsyncScheduler().runDelayed( From 921d706c1ebdcfbe93803187c98ec5532667536f Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 30 Dec 2023 21:19:29 +0100 Subject: [PATCH 086/113] Made Floodgate compatible with latest Spigot changes --- .../addon/data/SpigotDataHandler.java | 26 +++++---- .../geysermc/floodgate/util/ClassNames.java | 54 ++++++++++++++----- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java index 55dfc36e..75e7057c 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java +++ b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java @@ -167,31 +167,35 @@ private boolean checkAndHandleLogin(Object packet) throws Exception { } } - // set the player his GameProfile, we can't change the username without this GameProfile gameProfile = new GameProfile( player.getCorrectUniqueId(), player.getCorrectUsername() ); - setValue(packetListener, ClassNames.LOGIN_PROFILE, gameProfile); // we have to fake the offline player (login) cycle - // just like on Spigot: - - Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener); if (ClassNames.IS_PRE_1_20_2) { // 1.20.1 and below - - // LoginListener#initUUID - // new LoginHandler().fireEvents(); - + // - set profile, otherwise the username doesn't change + // - LoginListener#initUUID + // - new LoginHandler().fireEvents(); // and the tick of LoginListener will do the rest + Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener); + setValue(packetListener, ClassNames.LOGIN_PROFILE, gameProfile); ClassNames.INIT_UUID.invoke(packetListener); ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler); - } else { - // 1.20.2 and above we directly register the profile + } else if (!ClassNames.IS_POST_LOGIN_HANDLER) { + // 1.20.2 until somewhere in 1.20.4 we can directly register the profile + Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener); ClassNames.FIRE_LOGIN_EVENTS_GAME_PROFILE.invoke(loginHandler, gameProfile); + } else { + // somewhere during 1.20.4 md_5 moved stuff to CraftBukkit + + // LoginListener#callPlayerPreLoginEvents(GameProfile) + // LoginListener#startClientVerification(GameProfile) + ClassNames.CALL_PLAYER_PRE_LOGIN_EVENTS.invoke(packetListener, gameProfile); + ClassNames.START_CLIENT_VERIFICATION.invoke(packetListener, gameProfile); } ctx.pipeline().remove(this); diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 77e00cc7..b0eee8f0 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -59,11 +59,10 @@ public class ClassNames { public static final Class HANDSHAKE_PACKET; public static final Class LOGIN_START_PACKET; public static final Class LOGIN_LISTENER; - public static final Class LOGIN_HANDLER; @Nullable public static final Class CLIENT_INTENT; public static final Constructor CRAFT_OFFLINE_PLAYER_CONSTRUCTOR; - public static final Constructor LOGIN_HANDLER_CONSTRUCTOR; + @Nullable public static final Constructor LOGIN_HANDLER_CONSTRUCTOR; @Nullable public static final Constructor HANDSHAKE_PACKET_CONSTRUCTOR; public static final Field SOCKET_ADDRESS; @@ -84,13 +83,17 @@ public class ClassNames { @Nullable public static final Method INIT_UUID; @Nullable public static final Method FIRE_LOGIN_EVENTS; @Nullable public static final Method FIRE_LOGIN_EVENTS_GAME_PROFILE; + @Nullable public static final Method CALL_PLAYER_PRE_LOGIN_EVENTS; + @Nullable public static final Method START_CLIENT_VERIFICATION; public static final Field BUNGEE; public static final boolean IS_FOLIA; public static final boolean IS_PRE_1_20_2; + public static final boolean IS_POST_LOGIN_HANDLER; static { + // ahhhhhhh, this class should really be reworked at this point String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; SPIGOT_MAPPING_PREFIX = "net.minecraft.server." + version; @@ -167,6 +170,14 @@ public class ClassNames { INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID"); IS_PRE_1_20_2 = INIT_UUID != null; + // somewhere during 1.20.4 md_5 moved PreLogin logic to CraftBukkit + CALL_PLAYER_PRE_LOGIN_EVENTS = getMethod( + LOGIN_LISTENER, + "callPlayerPreLoginEvents", + GameProfile.class + ); + IS_POST_LOGIN_HANDLER = CALL_PLAYER_PRE_LOGIN_EVENTS != null; + if (IS_PRE_1_20_2) { Class packetListenerClass = getClassOrFallback( "net.minecraft.network.PacketListener", @@ -183,21 +194,36 @@ public class ClassNames { } checkNotNull(PACKET_LISTENER, "Packet listener"); - LOGIN_HANDLER = getClassOrFallback( - "net.minecraft.server.network.LoginListener$LoginHandler", - nmsPackage + "LoginListener$LoginHandler" - ); + if (IS_POST_LOGIN_HANDLER) { + makeAccessible(CALL_PLAYER_PRE_LOGIN_EVENTS); - LOGIN_HANDLER_CONSTRUCTOR = - ReflectionUtils.getConstructor(LOGIN_HANDLER, true, LOGIN_LISTENER); - checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor"); + START_CLIENT_VERIFICATION = getMethod(LOGIN_LISTENER, "b", GameProfile.class); + checkNotNull(START_CLIENT_VERIFICATION, "startClientVerification"); + makeAccessible(START_CLIENT_VERIFICATION); - FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents"); + LOGIN_HANDLER_CONSTRUCTOR = null; + FIRE_LOGIN_EVENTS = null; + FIRE_LOGIN_EVENTS_GAME_PROFILE = null; + } else { + Class loginHandler = getClassOrFallback( + "net.minecraft.server.network.LoginListener$LoginHandler", + nmsPackage + "LoginListener$LoginHandler" + ); - // LoginHandler().fireEvents(GameProfile) - FIRE_LOGIN_EVENTS_GAME_PROFILE = getMethod(LOGIN_HANDLER, "fireEvents", GameProfile.class); - checkNotNull(FIRE_LOGIN_EVENTS, FIRE_LOGIN_EVENTS_GAME_PROFILE, - "fireEvents from LoginHandler", "fireEvents(GameProfile) from LoginHandler"); + LOGIN_HANDLER_CONSTRUCTOR = + ReflectionUtils.getConstructor(loginHandler, true, LOGIN_LISTENER); + checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor"); + + FIRE_LOGIN_EVENTS = getMethod(loginHandler, "fireEvents"); + + // LoginHandler().fireEvents(GameProfile) + FIRE_LOGIN_EVENTS_GAME_PROFILE = getMethod(loginHandler, "fireEvents", + GameProfile.class); + checkNotNull(FIRE_LOGIN_EVENTS, FIRE_LOGIN_EVENTS_GAME_PROFILE, + "fireEvents from LoginHandler", "fireEvents(GameProfile) from LoginHandler"); + + START_CLIENT_VERIFICATION = null; + } PAPER_DISABLE_USERNAME_VALIDATION = getField(LOGIN_LISTENER, "iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation"); From 2876c577685dd8d023ecb78faedbdee17f7ba0d7 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 30 Dec 2023 21:22:59 +0100 Subject: [PATCH 087/113] We no longer use Jenkins --- Jenkinsfile | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index f9dbc474..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,30 +0,0 @@ -pipeline { - agent any - tools { - gradle 'Gradle 7' - jdk 'Java 17' - } - options { - buildDiscarder(logRotator(artifactNumToKeepStr: '5')) - } - stages { - stage ('Build') { - steps { - sh 'git submodule update --init --recursive' - rtGradleRun( - usesPlugin: true, - tool: 'Gradle 7', - buildFile: 'build.gradle.kts', - tasks: 'clean build', - ) - } - post { - success { - archiveArtifacts artifacts: '**/build/libs/floodgate-*.jar', - excludes: '**/floodgate-parent-*.jar,**/floodgate-api.jar,**/floodgate-core.jar', - fingerprint: true - } - } - } - } -} \ No newline at end of file From 94eabd7015447d69ec52b2e774eb50991397c6f1 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 18 Jan 2024 22:40:56 +0100 Subject: [PATCH 088/113] Add support for latest Velocity changes --- .../addon/data/VelocityProxyDataHandler.java | 11 +++++++++-- .../addon/data/VelocityServerDataHandler.java | 6 +++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java index b069543e..0c67c8a2 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java +++ b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityProxyDataHandler.java @@ -27,6 +27,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue; +import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallbackPrefixed; import static org.geysermc.floodgate.util.ReflectionUtils.getField; import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName; import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass; @@ -63,7 +64,10 @@ public final class VelocityProxyDataHandler extends CommonDataHandler { HANDSHAKE = getField(iic, "handshake"); checkNotNull(HANDSHAKE, "Handshake field cannot be null"); - HANDSHAKE_PACKET = getPrefixedClass("protocol.packet.Handshake"); + HANDSHAKE_PACKET = getClassOrFallbackPrefixed( + "protocol.packet.HandshakePacket", + "protocol.packet.Handshake" + ); checkNotNull(HANDSHAKE_PACKET, "Handshake packet class cannot be null"); HANDSHAKE_SERVER_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress"); @@ -73,7 +77,10 @@ public final class VelocityProxyDataHandler extends CommonDataHandler { REMOTE_ADDRESS = getField(minecraftConnection, "remoteAddress"); checkNotNull(REMOTE_ADDRESS, "remoteAddress cannot be null"); - SERVER_LOGIN_PACKET = getPrefixedClass("protocol.packet.ServerLogin"); + SERVER_LOGIN_PACKET = getClassOrFallbackPrefixed( + "protocol.packet.ServerLoginPacket", + "protocol.packet.ServerLogin" + ); checkNotNull(SERVER_LOGIN_PACKET, "ServerLogin packet class cannot be null"); diff --git a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityServerDataHandler.java b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityServerDataHandler.java index fb61f143..b68fafaa 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityServerDataHandler.java +++ b/velocity/src/main/java/org/geysermc/floodgate/addon/data/VelocityServerDataHandler.java @@ -28,6 +28,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.geysermc.floodgate.util.ReflectionUtils.castedInvoke; import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue; +import static org.geysermc.floodgate.util.ReflectionUtils.getClassOrFallbackPrefixed; import static org.geysermc.floodgate.util.ReflectionUtils.getField; import static org.geysermc.floodgate.util.ReflectionUtils.getMethod; import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass; @@ -55,7 +56,10 @@ public final class VelocityServerDataHandler extends ChannelOutboundHandlerAdapt private static final Method GET_PLAYER; static { - HANDSHAKE_PACKET = getPrefixedClass("protocol.packet.Handshake"); + HANDSHAKE_PACKET = getClassOrFallbackPrefixed( + "protocol.packet.HandshakePacket", + "protocol.packet.Handshake" + ); checkNotNull(HANDSHAKE_PACKET, "Handshake packet class cannot be null"); HANDSHAKE_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress"); From 19391fa253ba3aed62f74f34e084a36e5e29c4db Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 28 Jan 2024 22:51:20 +0000 Subject: [PATCH 089/113] Update Geyser version (#481) * Update Geyser version * Update Versions.kt --- build-logic/src/main/kotlin/Versions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 139a3ef5..612f8b36 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -24,7 +24,7 @@ */ object Versions { - const val geyserVersion = "2.1.2-SNAPSHOT" + const val geyserVersion = "2.2.1-SNAPSHOT" const val cumulusVersion = "1.1.2" const val eventsVersion = "1.1-SNAPSHOT" const val configUtilsVersion = "1.0-SNAPSHOT" @@ -39,4 +39,4 @@ object Versions { const val javaWebsocketVersion = "1.5.2" const val checkerQual = "3.19.0" -} \ No newline at end of file +} From 2886a71480a93241867fadc6c5ad59a9a70f9337 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 28 Jan 2024 22:52:16 +0000 Subject: [PATCH 090/113] Remove mention of maven in PR build (#482) --- .github/workflows/pullrequest.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 1ba39fbd..328b9444 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -20,7 +20,7 @@ jobs: java-version: '17' cache: 'gradle' - - name: Build with Maven + - name: Build run: ./gradlew build - name: Archive artifacts (Floodgate Bungee) @@ -42,4 +42,4 @@ jobs: if: success() with: name: Floodgate Velocity - path: velocity/build/libs/floodgate-velocity.jar \ No newline at end of file + path: velocity/build/libs/floodgate-velocity.jar From 7f38765010e28afb7fc5f0c7519e654413f11bd6 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 18 Feb 2024 15:36:44 +0100 Subject: [PATCH 091/113] Made the debug addon a bit more dumb --- .../geysermc/floodgate/addon/DebugAddon.java | 10 +- .../addon/debug/ChannelInDebugHandler.java | 17 +- .../addon/debug/ChannelOutDebugHandler.java | 18 +- .../addon/debug/StateChangeDetector.java | 193 ------------------ .../org/geysermc/floodgate/util/Utils.java | 17 +- 5 files changed, 19 insertions(+), 236 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/floodgate/addon/debug/StateChangeDetector.java diff --git a/core/src/main/java/org/geysermc/floodgate/addon/DebugAddon.java b/core/src/main/java/org/geysermc/floodgate/addon/DebugAddon.java index 7249e167..dcf9a7a6 100644 --- a/core/src/main/java/org/geysermc/floodgate/addon/DebugAddon.java +++ b/core/src/main/java/org/geysermc/floodgate/addon/DebugAddon.java @@ -29,9 +29,9 @@ import com.google.inject.name.Named; import io.netty.channel.Channel; import io.netty.channel.ChannelPipeline; +import java.util.concurrent.atomic.AtomicInteger; import org.geysermc.floodgate.addon.debug.ChannelInDebugHandler; import org.geysermc.floodgate.addon.debug.ChannelOutDebugHandler; -import org.geysermc.floodgate.addon.debug.StateChangeDetector; import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; @@ -57,16 +57,14 @@ public final class DebugAddon implements InjectorAddon { public void onInject(Channel channel, boolean toServer) { logger.info("Successfully called onInject. To server? " + toServer); - StateChangeDetector changeDetector = new StateChangeDetector( - channel, packetEncoder, packetDecoder, logger - ); + AtomicInteger packetCount = new AtomicInteger(); channel.pipeline().addBefore( packetEncoder, "floodgate_debug_out", - new ChannelOutDebugHandler(implementationName, toServer, changeDetector, logger) + new ChannelOutDebugHandler(implementationName, toServer, packetCount, logger) ).addBefore( packetDecoder, "floodgate_debug_in", - new ChannelInDebugHandler(implementationName, toServer, changeDetector, logger) + new ChannelInDebugHandler(implementationName, toServer, packetCount, logger) ); } diff --git a/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelInDebugHandler.java b/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelInDebugHandler.java index d1b1619c..bf1588e3 100644 --- a/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelInDebugHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelInDebugHandler.java @@ -30,25 +30,24 @@ import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import java.util.concurrent.atomic.AtomicInteger; import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.util.Utils; @Sharable public final class ChannelInDebugHandler extends SimpleChannelInboundHandler { private final String direction; private final FloodgateLogger logger; - - private final boolean toServer; - private final StateChangeDetector changeDetector; + private final AtomicInteger packetCount; public ChannelInDebugHandler( String implementationType, boolean toServer, - StateChangeDetector changeDetector, + AtomicInteger packetCount, FloodgateLogger logger) { this.direction = (toServer ? "Server -> " : "Player -> ") + implementationType; this.logger = logger; - this.toServer = toServer; - this.changeDetector = changeDetector; + this.packetCount = packetCount; } @Override @@ -56,14 +55,12 @@ protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { try { int index = msg.readerIndex(); - if (changeDetector.shouldPrintPacket(msg, !toServer)) { + if (packetCount.getAndIncrement() < Utils.MAX_DEBUG_PACKET_COUNT) { logger.info("{} {}:\n{}", direction, - changeDetector.getCurrentState(), + packetCount.get(), ByteBufUtil.prettyHexDump(msg) ); - - changeDetector.checkPacket(msg, !toServer); } // reset index diff --git a/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelOutDebugHandler.java b/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelOutDebugHandler.java index 05a80673..f4ab7acf 100644 --- a/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelOutDebugHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/addon/debug/ChannelOutDebugHandler.java @@ -30,25 +30,24 @@ import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; +import java.util.concurrent.atomic.AtomicInteger; import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.util.Utils; @Sharable public final class ChannelOutDebugHandler extends MessageToByteEncoder { private final String direction; private final FloodgateLogger logger; - - private final boolean toServer; - private final StateChangeDetector changeDetector; + private final AtomicInteger packetCount; public ChannelOutDebugHandler( String implementationType, boolean toServer, - StateChangeDetector changeDetector, + AtomicInteger packetCount, FloodgateLogger logger) { this.direction = implementationType + (toServer ? " -> Server" : " -> Player"); this.logger = logger; - this.toServer = toServer; - this.changeDetector = changeDetector; + this.packetCount = packetCount; } @Override @@ -56,16 +55,13 @@ protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) { try { int index = msg.readerIndex(); - if (changeDetector.shouldPrintPacket(msg, toServer)) { + if (packetCount.getAndIncrement() < Utils.MAX_DEBUG_PACKET_COUNT) { logger.info( "{} {}:\n{}", direction, - changeDetector.getCurrentState(), + packetCount.get(), ByteBufUtil.prettyHexDump(msg) ); - - // proxy acts as a client when it connects to a server - changeDetector.checkPacket(msg, toServer); } // reset index diff --git a/core/src/main/java/org/geysermc/floodgate/addon/debug/StateChangeDetector.java b/core/src/main/java/org/geysermc/floodgate/addon/debug/StateChangeDetector.java deleted file mode 100644 index 2c60a1c8..00000000 --- a/core/src/main/java/org/geysermc/floodgate/addon/debug/StateChangeDetector.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2019-2022 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/Floodgate - */ - -package org.geysermc.floodgate.addon.debug; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelPipeline; -import java.nio.charset.StandardCharsets; -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.util.Constants; -import org.geysermc.floodgate.util.Utils; - -public class StateChangeDetector { - private static volatile int pluginMessageToClientId = -1; - private static volatile int pluginMessageToServerId = -1; - - private final Channel channel; - private final FloodgateLogger logger; - private final String packetEncoderName; - private final String packetDecoderName; - - private volatile boolean enableCompressionNext; - private volatile State currentState = State.HANDSHAKE; - - public StateChangeDetector( - Channel channel, - String packetEncoderName, - String packetDecoderName, - FloodgateLogger logger) { - this.channel = channel; - this.packetEncoderName = packetEncoderName; - this.packetDecoderName = packetDecoderName; - this.logger = logger; - } - - /** - * Checks (and acts) if the current packet is one of the packets that we need to switch states. - * - * @param packet the packet to check - * @param fromClient if the packet is clientbound or serverbound - */ - public void checkPacket(ByteBuf packet, boolean fromClient) { - int index = packet.readerIndex(); - - if (enableCompressionNext) { - // data length - Utils.readVarInt(packet); - - fixCompressionPipes(); - enableCompressionNext = false; - } - - int packetId = Utils.readVarInt(packet); - - if (fromClient) { - if (currentState == State.HANDSHAKE && packetId == Constants.HANDSHAKE_PACKET_ID) { - // have to read the content to determine the next state - - // protocol version - Utils.readVarInt(packet); - // server address - int hostLength = Utils.readVarInt(packet); - // read server address + port (short = 2 bytes) - packet.readerIndex(packet.readerIndex() + hostLength + 2); - // next state - currentState = State.getById(Utils.readVarInt(packet)); - } - } else { - if (currentState == State.LOGIN) { - if (packetId == Constants.LOGIN_SUCCESS_PACKET_ID) { - currentState = State.PLAY; - } - if (packetId == Constants.SET_COMPRESSION_PACKET_ID) { - enableCompressionNext = true; - } - } - } - - // reset index - packet.readerIndex(index); - } - - private void fixCompressionPipes() { - // The previous packet was the compression packet, meaning that starting with this - // packet the data can already be compressed. The compression handler has been added - // directly before the packet encoder and decoder, so we have to reclaim that place. - // If we don't, we'll see the compressed data. - - ChannelPipeline pipeline = channel.pipeline(); - - ChannelHandler outDebug = pipeline.remove(ChannelOutDebugHandler.class); - ChannelHandler inDebug = pipeline.remove(ChannelInDebugHandler.class); - - pipeline.addBefore(packetEncoderName, "floodgate_debug_out", outDebug); - pipeline.addBefore(packetDecoderName, "floodgate_debug_in", inDebug); - } - - public boolean shouldPrintPacket(ByteBuf packet, boolean clientbound) { - return Constants.PRINT_ALL_PACKETS || - currentState == State.HANDSHAKE || currentState == State.LOGIN || - currentState != State.STATUS && shouldPrintPlayPacket(packet, clientbound); - } - - public boolean shouldPrintPlayPacket(ByteBuf packet, boolean clientbound) { - int index = packet.readerIndex(); - - int packetId = Utils.readVarInt(packet); - - // we're only interested in the plugin message packets - - // use cached packet ids - if (clientbound && pluginMessageToClientId != -1) { - return pluginMessageToClientId == packetId; - } - if (!clientbound && pluginMessageToServerId != -1) { - return pluginMessageToServerId == packetId; - } - - boolean shouldPrint = false; - - if (packet.isReadable()) { - // format plugin message packet: channel - remaining data - try { - int channelLength = Utils.readVarInt(packet); - - if (channelLength >= 1 && channelLength <= 128 && - packet.isReadable(channelLength)) { - - byte[] channelBytes = new byte[channelLength]; - packet.readBytes(channelBytes); - - String channelName = new String(channelBytes, StandardCharsets.UTF_8); - if (channelName.contains(":")) { - // some other packets will still match, - // but since plugin message packets are send early on - // we can almost know for certain that this is a plugin message packet - printIdentified(clientbound, packetId); - if (clientbound) { - pluginMessageToClientId = packetId; - } else { - pluginMessageToServerId = packetId; - } - shouldPrint = true; - } - } - } catch (RuntimeException ignored) { - // not the plugin message packet - } - } - - // reset index - packet.readerIndex(index); - - return shouldPrint; - } - - private void printIdentified(boolean clientbound, int packetId) { - logger.info( - "Identified plugin message packet ({}) as {} ({})", - clientbound ? "clientbound" : "serverbound", - packetId, - Integer.toHexString(packetId) - ); - } - - public State getCurrentState() { - return currentState; - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/util/Utils.java b/core/src/main/java/org/geysermc/floodgate/util/Utils.java index 19ef78de..cf4b7f1a 100644 --- a/core/src/main/java/org/geysermc/floodgate/util/Utils.java +++ b/core/src/main/java/org/geysermc/floodgate/util/Utils.java @@ -25,7 +25,6 @@ package org.geysermc.floodgate.util; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; import java.io.BufferedReader; @@ -47,6 +46,7 @@ public class Utils { private static final Pattern NON_UNIQUE_PREFIX = Pattern.compile("^\\w{0,16}$"); private static final Pattern DATABASE_NAME = Pattern.compile(Constants.DATABASE_NAME_FORMAT); + public static final int MAX_DEBUG_PACKET_COUNT = 25; /** * This method is used in Addons.
Most addons can be removed once the player associated to @@ -103,21 +103,6 @@ public static boolean isValidDatabaseName(String databaseName) { return DATABASE_NAME.matcher(databaseName).matches(); } - public static int readVarInt(ByteBuf buffer) { - int out = 0; - int count = 0; - byte current; - do { - current = buffer.readByte(); - out |= (current & 0x7F) << (count++ * 7); - - if (count > 5) { - throw new RuntimeException("VarInt is bigger then allowed"); - } - } while ((current & 0x80) != 0); - return out; - } - public static String getStackTrace(Throwable throwable) { StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); From 851ed5adc044302bd22ebf16e39a58a767373fed Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 28 Apr 2024 01:01:30 +0200 Subject: [PATCH 092/113] Support 1.20.5 spigot, update languages module, update Bungee dependency so the project builds (#498) --- bungee/build.gradle.kts | 4 ++-- core/src/main/resources/languages | 2 +- .../floodgate/addon/data/SpigotDataHandler.java | 4 ++-- .../org/geysermc/floodgate/util/ClassNames.java | 17 +++++++++++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index b438a04e..0d228850 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -1,4 +1,4 @@ -var bungeeCommit = "master-SNAPSHOT" +var bungeeVersion = "1.20-R0.3-SNAPSHOT" var gsonVersion = "2.8.0" var guavaVersion = "21.0" @@ -16,6 +16,6 @@ relocate("io.leangen.geantyref") relocate("org.yaml") // these dependencies are already present on the platform -provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", bungeeCommit) +provided("net.md-5", "bungeecord-proxy", bungeeVersion) provided("com.google.code.gson", "gson", gsonVersion) provided("com.google.guava", "guava", guavaVersion) diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 204f4fe4..df599a9b 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 204f4fe4920defac3a472e762d95233d0756f35f +Subproject commit df599a9bc9d7fce93a586591d6c0d625eefe4463 diff --git a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java index 75e7057c..36f34e9d 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java +++ b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java @@ -68,9 +68,9 @@ protected Object setHostname(Object handshakePacket, String hostname) throws Ill // 1.20.2 and above try { Object[] components = new Object[]{ - ClassNames.HANDSHAKE_PORT.get(handshakePacket), - hostname, ClassNames.HANDSHAKE_PROTOCOL.get(handshakePacket), + hostname, + ClassNames.HANDSHAKE_PORT.get(handshakePacket), ClassNames.HANDSHAKE_INTENTION.get(handshakePacket) }; diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index b0eee8f0..d93548c6 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -293,14 +293,23 @@ public class ClassNames { String.class, int.class, CLIENT_INTENT); checkNotNull(HANDSHAKE_PACKET_CONSTRUCTOR, "Handshake packet constructor"); - HANDSHAKE_PORT = getField(HANDSHAKE_PACKET, "a"); - checkNotNull(HANDSHAKE_PORT, "Handshake port"); - makeAccessible(HANDSHAKE_PORT); + Field a = getField(HANDSHAKE_PACKET, "a"); + checkNotNull(a, "Handshake \"a\" field (protocol version, or stream codec)"); + + if (a.getType().isPrimitive()) { // 1.20.2 - 1.20.4: a is the protocol version (int) + HANDSHAKE_PROTOCOL = a; + HANDSHAKE_PORT = getField(HANDSHAKE_PACKET, "c"); + } else { // 1.20.5: a is the stream_codec thing, so everything is shifted + HANDSHAKE_PROTOCOL = getField(HANDSHAKE_PACKET, "b"); + HANDSHAKE_PORT = getField(HANDSHAKE_PACKET, "d"); + } - HANDSHAKE_PROTOCOL = getField(HANDSHAKE_PACKET, "c"); checkNotNull(HANDSHAKE_PROTOCOL, "Handshake protocol"); makeAccessible(HANDSHAKE_PROTOCOL); + checkNotNull(HANDSHAKE_PORT, "Handshake port"); + makeAccessible(HANDSHAKE_PORT); + HANDSHAKE_INTENTION = getFieldOfType(HANDSHAKE_PACKET, CLIENT_INTENT); checkNotNull(HANDSHAKE_INTENTION, "Handshake intention"); makeAccessible(HANDSHAKE_INTENTION); From 58d71cb8eb4ed062134393eb705ac531c5bfbcb4 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 28 Apr 2024 07:18:35 -0700 Subject: [PATCH 093/113] Fix Publishing to the Downloads API (#499) * Update build process * Ensure BUILD_JSON env is init * Fallback to GH run number * Use tmp file for metadata.json Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .github/workflows/build.yml | 108 +++++++++++++++++----- .github/workflows/pullrequest.yml | 37 ++++++-- build-logic/src/main/kotlin/extensions.kt | 5 +- 3 files changed, 114 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a53a65eb..66cb9840 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,26 +5,69 @@ on: [push] jobs: build: runs-on: ubuntu-latest + env: + PROJECT: 'floodgate' steps: + - name: Set Build Number + env: + BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }} + run: | + BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1') + echo "BUILD_NUMBER=${BUILD_NUMBER:=$GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + - name: Checkout repository and submodules - uses: actions/checkout@v3 + # See https://github.com/actions/checkout/commits + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: recursive - - uses: actions/setup-java@v3 + - name: Validate Gradle Wrapper + # See https://github.com/gradle/wrapper-validation-action/commits + uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 + + # See https://github.com/actions/setup-java/commits + - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 with: java-version: 17 distribution: temurin - name: Build - uses: gradle/gradle-build-action@v2 + # See https://github.com/gradle/actions/commits + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 with: arguments: build cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }} + - name: Archive artifacts (Floodgate Bungee) + # See https://github.com/actions/upload-artifact/commits + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: success() + with: + name: Floodgate Bungee + path: bungee/build/libs/floodgate-bungee.jar + if-no-files-found: error + + - name: Archive artifacts (Floodgate Spigot) + # See https://github.com/actions/upload-artifact/commits + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: success() + with: + name: Floodgate Spigot + path: spigot/build/libs/floodgate-spigot.jar + if-no-files-found: error + + - name: Archive artifacts (Floodgate Velocity) + # See https://github.com/actions/upload-artifact/commits + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: success() + with: + name: Floodgate Velocity + path: velocity/build/libs/floodgate-velocity.jar + if-no-files-found: error + - name: Publish to Maven Repository if: ${{ github.repository == 'GeyserMC/Floodgate' }} - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 env: ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} @@ -32,8 +75,37 @@ jobs: arguments: publish cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }} + - name: Get Release Metadata + if: ${{ success() && github.repository == 'GeyserMC/Floodgate' && github.ref_name == 'master' }} + # See https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # main-11 + with: + appID: ${{ secrets.RELEASE_APP_ID }} + appPrivateKey: ${{ secrets.RELEASE_APP_PK }} + files: | + bungee:bungee/build/libs/floodgate-bungee.jar + spigot:spigot/build/libs/floodgate-spigot.jar + velocity:velocity/build/libs/floodgate-velocity.jar + releaseEnabled: false + saveMetadata: true + + - name: Update Generated Metadata + if: ${{ success() && github.repository == 'GeyserMC/Floodgate' && github.ref_name == 'master' }} + run: | + cat metadata.json + echo + mv metadata.json metadata.json.tmp + version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + jq --arg project "${PROJECT}" --arg version "${version}" ' + . + | .changes |= map({"commit", "summary", "message"}) + | .downloads |= map_values({"name", "sha256"}) + | {$project, "repo", $version, "number": .build, "changes", "downloads"} + ' metadata.json.tmp > metadata.json + cat metadata.json + - name: Publish to Downloads API - if: ${{ github.ref_name == 'master' && github.repository == 'GeyserMC/Floodgate' }} + if: ${{ success() && github.ref_name == 'master' && github.repository == 'GeyserMC/Floodgate' }} shell: bash env: DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} @@ -43,28 +115,18 @@ jobs: # Save the private key to a file echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa chmod 600 id_ecdsa - - # Set the project - project=floodgate - - # Get the version from gradle.properties - version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) - # Create the build folder - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/" - + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/" # Copy over artifacts - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ - - # Remove un-needed artifacts - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ./uploads/$project/$GITHUB_RUN_NUMBER/floodgate-api.jar ./uploads/$project/$GITHUB_RUN_NUMBER/floodgate-core.jar - - # Push the metadata - echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bungee/build/libs/floodgate-bungee.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" spigot/build/libs/floodgate-spigot.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" velocity/build/libs/floodgate-velocity.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ + # Run the build script + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - name: Notify Discord if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Floodgate' }} - uses: Tim203/actions-git-discord-webhook@main + # See https://github.com/Tim203/actions-git-discord-webhook/commits + uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff with: webhook_url: ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 328b9444..1b64603f 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -8,38 +8,55 @@ jobs: runs-on: ubuntu-latest steps: + - name: Set Build Number + run: | + echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + - name: Checkout repository and submodules - uses: actions/checkout@v3 + # See https://github.com/actions/checkout/commits + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: recursive + - name: Validate Gradle Wrapper + # See https://github.com/gradle/wrapper-validation-action/commits + uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 + - name: Set up JDK 17 - uses: actions/setup-java@v2 + # See https://github.com/actions/setup-java/commits + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 with: - distribution: 'temurin' - java-version: '17' - cache: 'gradle' + java-version: 17 + distribution: temurin - - name: Build - run: ./gradlew build + - name: Build Floodgate + # See https://github.com/gradle/actions/commits + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + with: + arguments: build + cache-read-only: true - name: Archive artifacts (Floodgate Bungee) - uses: actions/upload-artifact@v2 + # See https://github.com/actions/upload-artifact/commits + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: success() with: name: Floodgate Bungee path: bungee/build/libs/floodgate-bungee.jar + if-no-files-found: error - name: Archive artifacts (Floodgate Spigot) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: success() with: name: Floodgate Spigot path: spigot/build/libs/floodgate-spigot.jar + if-no-files-found: error - name: Archive artifacts (Floodgate Velocity) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: success() with: name: Floodgate Velocity path: velocity/build/libs/floodgate-velocity.jar + if-no-files-found: error diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index bbf7531c..11406872 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -49,7 +49,7 @@ fun Project.versionWithBranchName(): String = branchName().replace(Regex("[^0-9A-Za-z-_]"), "-") + '-' + version fun buildNumber(): Int = - (System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1 + (System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1 fun buildNumberAsString(): String = buildNumber().takeIf { it != -1 }?.toString() ?: "??" @@ -81,5 +81,4 @@ private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String = if (excludedOn and bit > 0) section else "" // todo remove these when we're not using Jenkins anymore -private fun jenkinsBranchName(): String? = System.getenv("BRANCH_NAME") -private fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER") \ No newline at end of file +private fun jenkinsBranchName(): String? = System.getenv("BRANCH_NAME") \ No newline at end of file From 0fa00a85ad067429294216ac0a2ffee6f17e7d33 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 28 Apr 2024 20:25:04 +0200 Subject: [PATCH 094/113] Support Paper's lack of CraftBukkit relocation --- .../geysermc/floodgate/util/ClassNames.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index d93548c6..9dbc1497 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -94,13 +94,26 @@ public class ClassNames { static { // ahhhhhhh, this class should really be reworked at this point - String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + + String[] versionSplit = Bukkit.getServer().getClass().getPackage().getName().split("\\."); + // Paper, since 1.20.5, no longer relocates CraftBukkit classes + // and NMS classes aren't relocated for a few versions now (both Spigot & Paper) + if (versionSplit.length <= 3 && getClassSilently("net.minecraft.server.MinecraftServer") == null) { + throw new IllegalStateException( + "Was unable to find net.minecraft.server.MinecraftServer. " + + "We don't support Mojmap yet" + ); + } + // Makes it that we don't have to lookup both the new and the old + // 'org.bukkit.craftbukkit. + version + CraftPlayer' will be .CraftPlayer on new + // versions and .v1_8R3.CraftPlayer on older versions + String version = versionSplit.length > 3 ? versionSplit[3] + '.' : ""; SPIGOT_MAPPING_PREFIX = "net.minecraft.server." + version; // SpigotSkinApplier Class craftPlayerClass = ReflectionUtils.getClass( - "org.bukkit.craftbukkit." + version + ".entity.CraftPlayer"); + "org.bukkit.craftbukkit." + version + "entity.CraftPlayer"); GET_PROFILE_METHOD = getMethod(craftPlayerClass, "getProfile"); checkNotNull(GET_PROFILE_METHOD, "Get profile method"); @@ -120,9 +133,9 @@ public class ClassNames { // WhitelistUtils Class craftServerClass = ReflectionUtils.getClass( - "org.bukkit.craftbukkit." + version + ".CraftServer"); + "org.bukkit.craftbukkit." + version + "CraftServer"); Class craftOfflinePlayerClass = ReflectionUtils.getCastedClass( - "org.bukkit.craftbukkit." + version + ".CraftOfflinePlayer"); + "org.bukkit.craftbukkit." + version + "CraftOfflinePlayer"); CRAFT_OFFLINE_PLAYER_CONSTRUCTOR = ReflectionUtils.getConstructor( craftOfflinePlayerClass, true, craftServerClass, GameProfile.class); From 7a5530596d69cd9a4d7c7218e0d5f7f742b45632 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 28 Apr 2024 22:36:17 +0200 Subject: [PATCH 095/113] Feature: Cloud 2.0, publishing setup fixes (#496) * - Update to cloud 2.0 - bump floodgate version to 2.2.3 - fix publishing setup - don't publish shadow jars, ensure api/core artifacts aren't shaded jars * - update bstats - fix alias -> description * tiny cleanup, fix whitelisting bedrock players when the linked java account is online (and shares the same name) * Update build process * Ensure BUILD_JSON env is init * Fallback to GH run number * update guice to 6.0.0 to be compatible with java 21 * update languages module * Support 1.20.5 spigot, update languages module, update Bungee dependency so the project builds * remove codemc repo, update cloud-paper to snapshot build for 1.20.5 support --------- Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com> --- .gitmodules | 2 +- api/build.gradle.kts | 11 + build-logic/settings.gradle.kts | 1 + build-logic/src/main/kotlin/Versions.kt | 6 +- .../floodgate.publish-conventions.gradle.kts | 6 + bungee/build.gradle.kts | 4 +- .../module/BungeePlatformModule.java | 13 +- core/build.gradle.kts | 16 +- .../floodgate/command/LinkAccountCommand.java | 25 +-- .../floodgate/command/TestCommand.java | 9 +- .../command/UnlinkAccountCommand.java | 17 +- .../floodgate/command/WhitelistCommand.java | 25 +-- .../command/main/FirewallCheckSubcommand.java | 4 +- .../floodgate/command/main/MainCommand.java | 19 +- .../command/main/VersionSubcommand.java | 4 +- .../platform/command/CommandUtil.java | 11 +- .../platform/command/FloodgateCommand.java | 14 +- .../platform/command/FloodgateSubCommand.java | 2 +- .../player/FloodgateCommandPreprocessor.java | 8 +- .../audience/FloodgateSenderMapper.java | 52 +++++ .../InvalidPlayerIdentifierException.java | 40 ++++ .../audience/PlayerAudienceArgument.java | 113 ++++++++++ .../audience/ProfileAudienceArgument.java | 206 ------------------ .../floodgate/register/CommandRegister.java | 2 +- .../floodgate/util/BrigadierUtils.java | 68 ++++++ gradle.properties | 2 +- spigot/build.gradle.kts | 6 +- .../floodgate/module/SpigotCommandModule.java | 15 +- velocity/build.gradle.kts | 4 +- .../module/VelocityPlatformModule.java | 15 +- 30 files changed, 394 insertions(+), 326 deletions(-) create mode 100644 build-logic/settings.gradle.kts create mode 100644 core/src/main/java/org/geysermc/floodgate/player/audience/FloodgateSenderMapper.java create mode 100644 core/src/main/java/org/geysermc/floodgate/player/audience/InvalidPlayerIdentifierException.java create mode 100644 core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java delete mode 100644 core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java create mode 100644 core/src/main/java/org/geysermc/floodgate/util/BrigadierUtils.java diff --git a/.gitmodules b/.gitmodules index 074c6a2c..f04fc7a9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "core/src/main/resources/languages"] path = core/src/main/resources/languages url = https://github.com/GeyserMC/languages - branch = l10n_floodgate + branch = floodgate \ No newline at end of file diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 4418b61a..70579bbc 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -1,3 +1,5 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + dependencies { api("org.geysermc.geyser", "common", Versions.geyserVersion) api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) @@ -5,3 +7,12 @@ dependencies { compileOnly("io.netty", "netty-transport", Versions.nettyVersion) } + +tasks { + named("jar") { + archiveClassifier.set("") + } + named("shadowJar") { + archiveClassifier.set("shaded") + } +} diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts new file mode 100644 index 00000000..30499ad2 --- /dev/null +++ b/build-logic/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "build-logic" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 612f8b36..183655f4 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -30,11 +30,11 @@ object Versions { const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.19.4-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" - const val guiceVersion = "5.1.0" + const val guiceVersion = "6.0.0" const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" - const val cloudVersion = "1.5.0" - const val bstatsVersion = "d2fbbd6823" + const val cloudVersion = "2.0.0-beta.2" + const val bstatsVersion = "3.0.2" const val javaWebsocketVersion = "1.5.2" diff --git a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts index 0f7b7618..75c054f8 100644 --- a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts @@ -12,4 +12,10 @@ indra { publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots") publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases") +} + +publishing { + // skip shadow jar from publishing. Workaround for https://github.com/johnrengelman/shadow/issues/651 + val javaComponent = project.components["java"] as AdhocComponentWithVariants + javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) { skip() } } \ No newline at end of file diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index 0d228850..69ab1120 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -4,12 +4,12 @@ var guavaVersion = "21.0" dependencies { api(projects.core) - implementation("cloud.commandframework", "cloud-bungee", Versions.cloudVersion) + implementation("org.incendo", "cloud-bungee", Versions.cloudVersion) } relocate("com.google.inject") relocate("net.kyori") -relocate("cloud.commandframework") +relocate("org.incendo.cloud") // used in cloud relocate("io.leangen.geantyref") // since 1.20 diff --git a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java index 4943d88c..ec256d69 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java +++ b/bungee/src/main/java/org/geysermc/floodgate/module/BungeePlatformModule.java @@ -25,9 +25,6 @@ package org.geysermc.floodgate.module; -import cloud.commandframework.CommandManager; -import cloud.commandframework.bungee.BungeeCommandManager; -import cloud.commandframework.execution.CommandExecutionCoordinator; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; @@ -35,7 +32,6 @@ import com.google.inject.name.Names; import java.util.logging.Logger; import lombok.RequiredArgsConstructor; -import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; import org.geysermc.floodgate.BungeePlugin; @@ -51,6 +47,7 @@ import org.geysermc.floodgate.platform.util.PlatformUtils; import org.geysermc.floodgate.player.FloodgateCommandPreprocessor; import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.player.audience.FloodgateSenderMapper; import org.geysermc.floodgate.pluginmessage.BungeePluginMessageRegistration; import org.geysermc.floodgate.pluginmessage.BungeePluginMessageUtils; import org.geysermc.floodgate.pluginmessage.BungeeSkinApplier; @@ -60,6 +57,9 @@ import org.geysermc.floodgate.util.BungeeCommandUtil; import org.geysermc.floodgate.util.BungeePlatformUtils; import org.geysermc.floodgate.util.LanguageManager; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bungee.BungeeCommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; @RequiredArgsConstructor public final class BungeePlatformModule extends AbstractModule { @@ -88,9 +88,8 @@ public Plugin bungeePlugin() { public CommandManager commandManager(CommandUtil commandUtil) { CommandManager commandManager = new BungeeCommandManager<>( plugin, - CommandExecutionCoordinator.simpleCoordinator(), - commandUtil::getUserAudience, - audience -> (CommandSender) audience.source() + ExecutionCoordinator.simpleCoordinator(), + new FloodgateSenderMapper<>(commandUtil) ); commandManager.registerCommandPreProcessor(new FloodgateCommandPreprocessor<>(commandUtil)); return commandManager; diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1df4ae95..7d3d4632 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,3 +1,5 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + plugins { id("floodgate.generate-templates") } @@ -13,10 +15,8 @@ dependencies { api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion) api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion) api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion) - api("cloud.commandframework", "cloud-core", Versions.cloudVersion) - - //todo use official dependency once https://github.com/Bastian/bstats-metrics/pull/118 is merged - api("com.github.Konicai.bstats-metrics", "bstats-base", Versions.bstatsVersion) + api("org.incendo", "cloud-core", Versions.cloudVersion) + api("org.bstats", "bstats-base", Versions.bstatsVersion) } // present on all platforms @@ -31,4 +31,10 @@ tasks { replaceToken("branch", branchName()) replaceToken("buildNumber", buildNumber()) } -} + named("jar") { + archiveClassifier.set("") + } + named("shadowJar") { + archiveClassifier.set("shaded") + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java b/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java index fe8695fd..7c06429d 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/LinkAccountCommand.java @@ -26,12 +26,8 @@ package org.geysermc.floodgate.command; import static org.geysermc.floodgate.command.CommonCommandMessage.CHECK_CONSOLE; +import static org.incendo.cloud.parser.standard.StringParser.stringParser; -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.Command; -import cloud.commandframework.CommandManager; -import cloud.commandframework.arguments.standard.StringArgument; -import cloud.commandframework.context.CommandContext; import com.google.inject.Inject; import lombok.Getter; import lombok.NoArgsConstructor; @@ -46,9 +42,13 @@ import org.geysermc.floodgate.platform.command.TranslatableMessage; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience.PlayerAudience; +import org.geysermc.floodgate.player.audience.PlayerAudienceArgument; import org.geysermc.floodgate.player.audience.ProfileAudience; -import org.geysermc.floodgate.player.audience.ProfileAudienceArgument; import org.geysermc.floodgate.util.Constants; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.description.Description; @NoArgsConstructor public final class LinkAccountCommand implements FloodgateCommand { @@ -56,20 +56,19 @@ public final class LinkAccountCommand implements FloodgateCommand { @Inject private FloodgateLogger logger; @Override - public Command buildCommand(CommandManager commandManager) { + public Command buildCommand(CommandManager commandManager) { return commandManager.commandBuilder("linkaccount", - ArgumentDescription.of("Link your Java account with your Bedrock account")) + Description.of("Link your Java account with your Bedrock account")) .senderType(PlayerAudience.class) .permission(Permission.COMMAND_LINK.get()) - .argument(ProfileAudienceArgument.of("player", true)) - .argument(StringArgument.optional("code")) + .argument(PlayerAudienceArgument.ofAnyUsernameBoth("player")) + .optional("code", stringParser()) .handler(this::execute) .build(); } - @Override - public void execute(CommandContext context) { - UserAudience sender = context.getSender(); + public void execute(CommandContext context) { + UserAudience sender = context.sender(); PlayerLink link = api.getPlayerLink(); diff --git a/core/src/main/java/org/geysermc/floodgate/command/TestCommand.java b/core/src/main/java/org/geysermc/floodgate/command/TestCommand.java index f950da04..10213c78 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/TestCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/TestCommand.java @@ -25,14 +25,14 @@ package org.geysermc.floodgate.command; -import cloud.commandframework.Command; -import cloud.commandframework.CommandManager; -import cloud.commandframework.context.CommandContext; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.util.Constants; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; public class TestCommand implements FloodgateCommand { @Override @@ -43,10 +43,9 @@ public Command buildCommand(CommandManager commandMa .build(); } - @Override public void execute(CommandContext context) { int players = FloodgateApi.getInstance().getPlayers().size(); - context.getSender().sendMessage(String.valueOf(players)); + context.sender().sendMessage(String.valueOf(players)); } @Override diff --git a/core/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java b/core/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java index 1c5b0444..3ba4682b 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/UnlinkAccountCommand.java @@ -27,10 +27,6 @@ import static org.geysermc.floodgate.command.CommonCommandMessage.CHECK_CONSOLE; -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.Command; -import cloud.commandframework.CommandManager; -import cloud.commandframework.context.CommandContext; import com.google.inject.Inject; import lombok.Getter; import lombok.NoArgsConstructor; @@ -44,24 +40,27 @@ import org.geysermc.floodgate.player.UserAudience.PlayerAudience; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.command.util.Permission; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.description.Description; @NoArgsConstructor public final class UnlinkAccountCommand implements FloodgateCommand { @Inject private FloodgateApi api; @Override - public Command buildCommand(CommandManager commandManager) { + public Command buildCommand(CommandManager commandManager) { return commandManager.commandBuilder("unlinkaccount", - ArgumentDescription.of("Unlink your Java account from your Bedrock account")) + Description.of("Unlink your Java account from your Bedrock account")) .senderType(PlayerAudience.class) .permission(Permission.COMMAND_UNLINK.get()) .handler(this::execute) .build(); } - @Override - public void execute(CommandContext context) { - UserAudience sender = context.getSender(); + public void execute(CommandContext context) { + UserAudience sender = context.sender(); PlayerLink link = api.getPlayerLink(); diff --git a/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java b/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java index b87a20ee..54c5efcb 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/WhitelistCommand.java @@ -27,10 +27,6 @@ import static org.geysermc.floodgate.command.CommonCommandMessage.CHECK_CONSOLE; -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.Command; -import cloud.commandframework.CommandManager; -import cloud.commandframework.context.CommandContext; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.inject.Inject; @@ -46,10 +42,14 @@ import org.geysermc.floodgate.platform.command.TranslatableMessage; import org.geysermc.floodgate.platform.util.PlayerType; import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.player.audience.PlayerAudienceArgument; import org.geysermc.floodgate.player.audience.ProfileAudience; -import org.geysermc.floodgate.player.audience.ProfileAudienceArgument; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.HttpClient; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.description.Description; public class WhitelistCommand implements FloodgateCommand { @Inject private FloodgateConfig config; @@ -59,23 +59,23 @@ public class WhitelistCommand implements FloodgateCommand { @Override public Command buildCommand(CommandManager commandManager) { Command.Builder builder = commandManager.commandBuilder("fwhitelist", - ArgumentDescription.of("Easy way to whitelist Bedrock players")) + Description.of("Easy way to whitelist Bedrock players")) .permission(Permission.COMMAND_WHITELIST.get()); commandManager.command(builder .literal("add", "a") - .argument(ProfileAudienceArgument.of("player", true, true, PlayerType.ONLY_BEDROCK)) + .argument(PlayerAudienceArgument.ofAnyIdentifierBedrock("player")) .handler(context -> performCommand(context, true))); return builder .literal("remove", "r") - .argument(ProfileAudienceArgument.of("player", true, true, PlayerType.ONLY_BEDROCK)) + .argument(PlayerAudienceArgument.ofAnyIdentifierBedrock("player")) .handler(context -> performCommand(context, false)) .build(); } public void performCommand(CommandContext context, boolean add) { - UserAudience sender = context.getSender(); + UserAudience sender = context.sender(); ProfileAudience profile = context.get("player"); UUID uuid = profile.uuid(); String name = profile.username(); @@ -114,7 +114,7 @@ public void performCommand(CommandContext context, boolean add) { name = name.substring(config.getUsernamePrefix().length()); } - if (name.length() < 1 || name.length() > 16) { + if (name.isEmpty() || name.length() > 16) { sender.sendMessage(Message.INVALID_USERNAME); return; } @@ -181,11 +181,6 @@ public void performCommand(CommandContext context, boolean add) { }); } - @Override - public void execute(CommandContext context) { - // ignored, all the logic is in the other method - } - @Override public boolean shouldRegister(FloodgateConfig config) { // currently only Spigot (our only non-Proxy platform) has a whitelist build-in. diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java index 6fa989f5..be64d92a 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/FirewallCheckSubcommand.java @@ -27,7 +27,6 @@ import static org.geysermc.floodgate.util.Constants.COLOR_CHAR; -import cloud.commandframework.context.CommandContext; import com.google.gson.JsonElement; import com.google.inject.Inject; import it.unimi.dsi.fastutil.Pair; @@ -41,6 +40,7 @@ import org.geysermc.floodgate.util.HttpClient; import org.geysermc.floodgate.util.HttpClient.HttpResponse; import org.geysermc.floodgate.util.Utils; +import org.incendo.cloud.context.CommandContext; final class FirewallCheckSubcommand extends FloodgateSubCommand { @Inject @@ -63,7 +63,7 @@ public Permission permission() { @Override public void execute(CommandContext context) { - UserAudience sender = context.getSender(); + UserAudience sender = context.sender(); executeChecks( globalApiCheck(sender) ).whenComplete((response, $) -> diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java index 446e8106..801676e4 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/MainCommand.java @@ -27,17 +27,17 @@ import static org.geysermc.floodgate.util.Constants.COLOR_CHAR; -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.Command; -import cloud.commandframework.Command.Builder; -import cloud.commandframework.CommandManager; -import cloud.commandframework.context.CommandContext; import java.util.Locale; import org.geysermc.floodgate.command.util.Permission; import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.platform.command.SubCommands; import org.geysermc.floodgate.player.UserAudience; +import org.incendo.cloud.Command; +import org.incendo.cloud.Command.Builder; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.description.Description; public final class MainCommand extends SubCommands implements FloodgateCommand { public MainCommand() { @@ -49,14 +49,14 @@ public MainCommand() { public Command buildCommand(CommandManager commandManager) { Builder builder = commandManager.commandBuilder( "floodgate", - ArgumentDescription.of("A set of Floodgate related actions in one command")) + Description.of("A set of Floodgate related actions in one command")) .senderType(UserAudience.class) .permission(Permission.COMMAND_MAIN.get()) .handler(this::execute); for (FloodgateSubCommand subCommand : subCommands()) { commandManager.command(builder - .literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description()) + .literal(subCommand.name().toLowerCase(Locale.ROOT), Description.of(subCommand.description())) .permission(subCommand.permission().get()) .handler(subCommand::execute) ); @@ -66,12 +66,11 @@ public Command buildCommand(CommandManager commandMa return builder.build(); } - @Override public void execute(CommandContext context) { StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n"); for (FloodgateSubCommand subCommand : subCommands()) { - if (context.getSender().hasPermission(subCommand.permission().get())) { + if (context.sender().hasPermission(subCommand.permission().get())) { helpMessage.append('\n').append(COLOR_CHAR).append('b') .append(subCommand.name().toLowerCase(Locale.ROOT)) .append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7') @@ -79,6 +78,6 @@ public void execute(CommandContext context) { } } - context.getSender().sendMessage(helpMessage.toString()); + context.sender().sendMessage(helpMessage.toString()); } } diff --git a/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java b/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java index 985c47c1..961c1735 100644 --- a/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java +++ b/core/src/main/java/org/geysermc/floodgate/command/main/VersionSubcommand.java @@ -27,7 +27,6 @@ import static org.geysermc.floodgate.util.Constants.COLOR_CHAR; -import cloud.commandframework.context.CommandContext; import com.google.gson.JsonObject; import com.google.inject.Inject; import com.google.inject.name.Named; @@ -38,6 +37,7 @@ import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.HttpClient; +import org.incendo.cloud.context.CommandContext; public class VersionSubcommand extends FloodgateSubCommand { @Inject @@ -67,7 +67,7 @@ public Permission permission() { @Override public void execute(CommandContext context) { - UserAudience sender = context.getSender(); + UserAudience sender = context.sender(); sender.sendMessage(String.format( COLOR_CHAR + "7You're currently on " + COLOR_CHAR + "b%s" + COLOR_CHAR + "7 (branch: " + COLOR_CHAR + "b%s" + COLOR_CHAR + "7)\n" + diff --git a/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java b/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java index d159a29e..17bf555b 100644 --- a/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/command/CommandUtil.java @@ -112,11 +112,6 @@ public abstract class CommandUtil { return usernames; } - /** - * - * @param uuid - * @return - */ public abstract Object getPlayerByUuid(@NonNull UUID uuid); public Object getPlayerByUuid(@NonNull UUID uuid, PlayerType limitTo) { @@ -125,15 +120,15 @@ public Object getPlayerByUuid(@NonNull UUID uuid, PlayerType limitTo) { public abstract Object getPlayerByUsername(@NonNull String username); - public Object getPlayerByUsername(@NonNull String username, PlayerType limitTo) { - return applyPlayerTypeFilter(getPlayerByUsername(username), limitTo, username); + public Object getPlayerByUsername(@NonNull String username, PlayerType filter) { + return applyPlayerTypeFilter(getPlayerByUsername(username), filter, username); } protected Object applyPlayerTypeFilter(Object player, PlayerType filter, Object fallback) { if (filter == ALL_PLAYERS || player instanceof String || player instanceof UUID) { return player; } - return (filter == ONLY_BEDROCK) == api.isFloodgatePlayer(getUuidFromSource(player)) + return (filter == ONLY_BEDROCK) == api.isFloodgateId(getUuidFromSource(player)) ? player : fallback; } diff --git a/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateCommand.java b/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateCommand.java index f61c336e..80a115da 100644 --- a/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateCommand.java @@ -25,11 +25,10 @@ package org.geysermc.floodgate.platform.command; -import cloud.commandframework.Command; -import cloud.commandframework.CommandManager; -import cloud.commandframework.context.CommandContext; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.player.UserAudience; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; /** The base class for every Floodgate command. */ public interface FloodgateCommand { @@ -39,14 +38,7 @@ public interface FloodgateCommand { * @param commandManager the manager to create a command * @return the command to register */ - Command buildCommand(CommandManager commandManager); - - /** - * Called when the command created in {@link #buildCommand(CommandManager)} is executed. - * - * @param context the context of the executed command - */ - void execute(CommandContext context); + Command buildCommand(CommandManager commandManager); /** * Called by the CommandRegister to check if the command should be added given the config. diff --git a/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java b/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java index 25515ddc..fcf4b905 100644 --- a/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/platform/command/FloodgateSubCommand.java @@ -25,9 +25,9 @@ package org.geysermc.floodgate.platform.command; -import cloud.commandframework.context.CommandContext; import org.geysermc.floodgate.command.util.Permission; import org.geysermc.floodgate.player.UserAudience; +import org.incendo.cloud.context.CommandContext; public abstract class FloodgateSubCommand { public abstract String name(); diff --git a/core/src/main/java/org/geysermc/floodgate/player/FloodgateCommandPreprocessor.java b/core/src/main/java/org/geysermc/floodgate/player/FloodgateCommandPreprocessor.java index 104516de..54e68079 100644 --- a/core/src/main/java/org/geysermc/floodgate/player/FloodgateCommandPreprocessor.java +++ b/core/src/main/java/org/geysermc/floodgate/player/FloodgateCommandPreprocessor.java @@ -25,14 +25,14 @@ package org.geysermc.floodgate.player; -import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext; -import cloud.commandframework.execution.preprocessor.CommandPreprocessor; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.platform.command.CommandUtil; +import org.incendo.cloud.execution.preprocessor.CommandPreprocessingContext; +import org.incendo.cloud.execution.preprocessor.CommandPreprocessor; /** - * Command preprocessor which decorated incoming {@link cloud.commandframework.context.CommandContext} + * Command preprocessor which decorated incoming {@link org.incendo.cloud.context.CommandContext} * with Floodgate specific objects * * @param Command sender type @@ -44,6 +44,6 @@ public final class FloodgateCommandPreprocessor implements CommandPreprocesso @Override public void accept(@NonNull CommandPreprocessingContext context) { - context.getCommandContext().store("CommandUtil", commandUtil); + context.commandContext().store("CommandUtil", commandUtil); } } diff --git a/core/src/main/java/org/geysermc/floodgate/player/audience/FloodgateSenderMapper.java b/core/src/main/java/org/geysermc/floodgate/player/audience/FloodgateSenderMapper.java new file mode 100644 index 00000000..632ae5aa --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/player/audience/FloodgateSenderMapper.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2024 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/Floodgate + */ + +package org.geysermc.floodgate.player.audience; + + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.platform.command.CommandUtil; +import org.geysermc.floodgate.player.UserAudience; +import org.incendo.cloud.SenderMapper; + +public class FloodgateSenderMapper implements SenderMapper { + + private final CommandUtil commandUtil; + + public FloodgateSenderMapper(CommandUtil commandUtil) { + this.commandUtil = commandUtil; + } + + @Override + public @NonNull UserAudience map(@NonNull T base) { + return this.commandUtil.getUserAudience(base); + } + + @SuppressWarnings("unchecked") + @Override + public @NonNull T reverse(@NonNull UserAudience mapped) { + return (T) mapped.source(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/floodgate/player/audience/InvalidPlayerIdentifierException.java b/core/src/main/java/org/geysermc/floodgate/player/audience/InvalidPlayerIdentifierException.java new file mode 100644 index 00000000..d6692680 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/player/audience/InvalidPlayerIdentifierException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2024 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/Floodgate + */ + +package org.geysermc.floodgate.player.audience; + +import org.checkerframework.checker.nullness.qual.NonNull; + +public final class InvalidPlayerIdentifierException extends IllegalArgumentException { + + public InvalidPlayerIdentifierException(@NonNull String message) { + super(message); + } + + @Override + public @NonNull Throwable fillInStackTrace() { + return this; + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java b/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java new file mode 100644 index 00000000..3829db3a --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019-2024 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/Floodgate + */ + +package org.geysermc.floodgate.player.audience; + +import static org.incendo.cloud.parser.standard.StringParser.quotedStringParser; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import org.geysermc.floodgate.platform.command.CommandUtil; +import org.geysermc.floodgate.platform.util.PlayerType; +import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.util.BrigadierUtils; +import org.incendo.cloud.component.CommandComponent; +import org.incendo.cloud.parser.ArgumentParseResult; +import org.incendo.cloud.suggestion.Suggestion; + +public class PlayerAudienceArgument { + + public static CommandComponent.Builder ofAnyIdentifierBedrock(String name) { + return of(name, true, true, PlayerType.ONLY_BEDROCK); + } + + public static CommandComponent.Builder ofAnyUsernameBoth(String name) { + return of(name, false, true, PlayerType.ALL_PLAYERS); + } + + private static CommandComponent.Builder of(String name, boolean allowUuid, boolean allowOffline, PlayerType limitTo) { + return CommandComponent.builder() + .name(name) + .parser(quotedStringParser().flatMapSuccess(ProfileAudience.class, + (context, input) -> { + CommandUtil commandUtil = context.get("CommandUtil"); + + ProfileAudience profileAudience; + if (input.length() > 16) { + // This must be a UUID. + if (!allowUuid) { + return ArgumentParseResult.failureFuture( + new InvalidPlayerIdentifierException( + "UUID is not allowed here")); + } + + if (input.length() != 32 && input.length() != 36) { + // Neither UUID without dashes nor with dashes. + return ArgumentParseResult.failureFuture( + new InvalidPlayerIdentifierException( + "Expected player name/UUID")); + } + + try { + // We only want to make sure the UUID is valid here. + Object player = commandUtil.getPlayerByUuid( + UUID.fromString(input), limitTo); + profileAudience = commandUtil.getProfileAudience(player, + allowOffline); + } catch (final IllegalArgumentException ignored) { + return ArgumentParseResult.failureFuture( + new InvalidPlayerIdentifierException( + "Invalid UUID '" + input + "'")); + } + } else { + // This is a username. + Object player = commandUtil.getPlayerByUsername(input, limitTo); + profileAudience = commandUtil.getProfileAudience(player, + allowOffline); + } + + if (profileAudience == null) { + return ArgumentParseResult.failureFuture( + new InvalidPlayerIdentifierException( + "Invalid player '" + input + "'")); + } + + return ArgumentParseResult.successFuture(profileAudience); + })) + .suggestionProvider((context, input) -> { + CommandUtil commandUtil = context.get("CommandUtil"); + + boolean quoted = input.remainingInput().startsWith("\""); + List suggestions = new ArrayList(); + for (final String player : commandUtil.getOnlineUsernames(limitTo)) { + suggestions.add( + Suggestion.simple(BrigadierUtils.escapeIfRequired(player, quoted))); + } + return CompletableFuture.completedFuture(suggestions); + }); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java b/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java deleted file mode 100644 index 9c425637..00000000 --- a/core/src/main/java/org/geysermc/floodgate/player/audience/ProfileAudienceArgument.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2019-2022 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/Floodgate - */ - -package org.geysermc.floodgate.player.audience; - -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.context.CommandContext; -import com.google.common.collect.ImmutableList; -import java.util.List; -import java.util.Locale; -import java.util.Queue; -import java.util.UUID; -import lombok.RequiredArgsConstructor; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.floodgate.platform.command.CommandUtil; -import org.geysermc.floodgate.platform.util.PlayerType; -import org.geysermc.floodgate.player.UserAudience; - -public class ProfileAudienceArgument extends CommandArgument { - private ProfileAudienceArgument(@NonNull String name, ProfileAudienceParser parser) { - super(true, name, parser, ProfileAudience.class); - } - - public static ProfileAudienceArgument of( - String name, - boolean allowUuid, - boolean allowOffline, - PlayerType limitTo) { - return new ProfileAudienceArgument(name, - new ProfileAudienceParser(allowUuid, allowOffline, limitTo)); - } - - public static ProfileAudienceArgument of( - String name, - boolean allowOffline, - PlayerType limitTo) { - return of(name, false, allowOffline, limitTo); - } - - public static ProfileAudienceArgument ofOnline(String name, PlayerType limitTo) { - return of(name, false, false, limitTo); - } - - public static ProfileAudienceArgument ofOnline(String name, boolean allowUuid) { - return of(name, allowUuid, false, PlayerType.ALL_PLAYERS); - } - - public static CommandArgument ofOnline(String name) { - return of(name, false, false, PlayerType.ALL_PLAYERS); - } - - public static ProfileAudienceArgument of(String name, boolean allowOffline) { - return of(name, false, allowOffline, PlayerType.ALL_PLAYERS); - } - - @RequiredArgsConstructor - public static final class ProfileAudienceParser - implements ArgumentParser { - - private final boolean allowUuid; - private final boolean allowOffline; - private final PlayerType limitTo; - - @Override - public @NonNull ArgumentParseResult parse( - @NonNull CommandContext<@NonNull UserAudience> commandContext, - @NonNull Queue<@NonNull String> inputQueue) { - CommandUtil commandUtil = commandContext.get("CommandUtil"); - - String input = inputQueue.poll(); - if (input == null || input.length() < 3) { - return ArgumentParseResult.failure( - new NullPointerException("Expected player name/UUID")); - } - - if (input.startsWith("\"")) { - if (input.endsWith("\"")) { - // Remove quotes from both sides of this string - input = input.substring(1); - input = input.substring(0, input.length() - 1); - } else { - // Multi-line - StringBuilder builder = new StringBuilder(input); - while (!inputQueue.isEmpty()) { - String string = inputQueue.remove(); - builder.append(' ').append(string); - if (string.endsWith("\"")) { - break; - } - } - - if (builder.lastIndexOf("\"") != builder.length() - 1) { - return ArgumentParseResult.failure( - new InvalidPlayerIdentifierException("Malformed string provided; " + - "no end quotes found!")); - } - - builder.deleteCharAt(0); - builder.deleteCharAt(builder.length() - 1); - input = builder.toString(); - } - } - - ProfileAudience profileAudience; - - if (input.length() > 16) { - // This must be a UUID. - if (!allowUuid) { - return ArgumentParseResult.failure( - new InvalidPlayerIdentifierException("UUID is not allowed here")); - } - - if (input.length() != 32 && input.length() != 36) { - // Neither UUID without dashes nor with dashes. - return ArgumentParseResult.failure( - new InvalidPlayerIdentifierException("Expected player name/UUID")); - } - - try { - // We only want to make sure the UUID is valid here. - Object player = commandUtil.getPlayerByUuid(UUID.fromString(input), limitTo); - profileAudience = commandUtil.getProfileAudience(player, allowOffline); - } catch (final IllegalArgumentException ignored) { - return ArgumentParseResult.failure( - new InvalidPlayerIdentifierException("Invalid UUID '" + input + "'")); - } - } else { - // This is a username. - Object player = commandUtil.getPlayerByUsername(input, limitTo); - profileAudience = commandUtil.getProfileAudience(player, allowOffline); - } - - if (profileAudience == null) { - return ArgumentParseResult.failure( - new InvalidPlayerIdentifierException("Invalid player '" + input + "'")); - } - - return ArgumentParseResult.success(profileAudience); - } - - @Override - public @NonNull List suggestions( - @NonNull CommandContext commandContext, - @NonNull String input) { - CommandUtil commandUtil = commandContext.get("CommandUtil"); - String trimmedInput = input.trim(); - - if (trimmedInput.isEmpty()) { - return ImmutableList.copyOf(commandUtil.getOnlineUsernames(limitTo)); - } - - String lowercaseInput = input.toLowerCase(Locale.ROOT); - ImmutableList.Builder builder = ImmutableList.builder(); - - for (final String player : commandUtil.getOnlineUsernames(limitTo)) { - if (player.toLowerCase(Locale.ROOT).startsWith(lowercaseInput)) { - builder.add(player); - } - } - - return builder.build(); - } - - @Override - public boolean isContextFree() { - return true; - } - } - - public static final class InvalidPlayerIdentifierException extends IllegalArgumentException { - private static final long serialVersionUID = -6500019324607183855L; - - public InvalidPlayerIdentifierException(@NonNull String message) { - super(message); - } - - @Override - public @NonNull Throwable fillInStackTrace() { - return this; - } - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/register/CommandRegister.java b/core/src/main/java/org/geysermc/floodgate/register/CommandRegister.java index 2eed7d26..11ebd0fe 100644 --- a/core/src/main/java/org/geysermc/floodgate/register/CommandRegister.java +++ b/core/src/main/java/org/geysermc/floodgate/register/CommandRegister.java @@ -25,7 +25,6 @@ package org.geysermc.floodgate.register; -import cloud.commandframework.CommandManager; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; @@ -33,6 +32,7 @@ import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.player.UserAudience; +import org.incendo.cloud.CommandManager; /** * This class is responsible for registering commands to the command register of the platform that diff --git a/core/src/main/java/org/geysermc/floodgate/util/BrigadierUtils.java b/core/src/main/java/org/geysermc/floodgate/util/BrigadierUtils.java new file mode 100644 index 00000000..50c1eb5d --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/util/BrigadierUtils.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019-2024 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +/* +Code taken from Brigadier's StringArgumentType and StringReader + */ +public final class BrigadierUtils { + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public static boolean isAllowedInUnquotedString(char c) { + return c >= '0' && c <= '9' || + c >= 'A' && c <= 'Z' || + c >= 'a' && c <= 'z' || + c == '_' || c == '-' || + c == '.' || c == '+'; + } + + public static String escapeIfRequired(String input, boolean quoted) { + if (quoted) { + return escape(input); + } + + for (final char c : input.toCharArray()) { + if (!isAllowedInUnquotedString(c)) { + return "\"" + input + "\""; + } + } + return input; + } + + private static String escape(final String input) { + final StringBuilder result = new StringBuilder("\""); + + for (int i = 0; i < input.length(); i++) { + final char c = input.charAt(i); + if (c == '\\' || c == '"') { + result.append('\\'); + } + result.append(c); + } + + result.append("\""); + return result.toString(); + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index af961a84..8e836211 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ org.gradle.configureondemand=true org.gradle.caching=true org.gradle.parallel=true -version=2.2.2-SNAPSHOT \ No newline at end of file +version=2.2.3-SNAPSHOT \ No newline at end of file diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index c0dad7af..193fc27e 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -13,7 +13,9 @@ indra { dependencies { api(projects.core) - implementation("cloud.commandframework", "cloud-bukkit", Versions.cloudVersion) + // TODO move to release once cloud-paper releases for 1.20.5 + // https://repo.papermc.io/#browse/browse:maven-public:org%2Fincendo%2Fcloud-paper%2F2.0.0-SNAPSHOT%2F2.0.0-20240427.220226-58 + implementation("org.incendo", "cloud-paper", "2.0.0-20240427.220226-58") // hack to make pre 1.12 work implementation("com.google.guava", "guava", guavaVersion) @@ -26,7 +28,7 @@ dependencies { relocate("com.google.inject") relocate("net.kyori") -relocate("cloud.commandframework") +relocate("org.incendo.cloud") relocate("io.leangen.geantyref") // used in cloud // hack to make pre 1.12 work relocate("com.google.common") diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java index 4db0c9f6..959c4ac0 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java @@ -25,15 +25,11 @@ package org.geysermc.floodgate.module; -import cloud.commandframework.CommandManager; -import cloud.commandframework.bukkit.BukkitCommandManager; -import cloud.commandframework.execution.CommandExecutionCoordinator; import com.google.inject.Provides; import com.google.inject.Singleton; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginManager; import org.geysermc.floodgate.SpigotPlugin; @@ -41,6 +37,10 @@ import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.player.FloodgateCommandPreprocessor; import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.player.audience.FloodgateSenderMapper; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.paper.PaperCommandManager; @RequiredArgsConstructor public final class SpigotCommandModule extends CommandModule { @@ -56,11 +56,10 @@ protected void configure() { @Singleton @SneakyThrows public CommandManager commandManager(CommandUtil commandUtil) { - CommandManager commandManager = new BukkitCommandManager<>( + CommandManager commandManager = new PaperCommandManager<>( plugin, - CommandExecutionCoordinator.simpleCoordinator(), - commandUtil::getUserAudience, - audience -> (CommandSender) audience.source() + ExecutionCoordinator.simpleCoordinator(), + new FloodgateSenderMapper<>(commandUtil) ); commandManager.registerCommandPreProcessor(new FloodgateCommandPreprocessor<>(commandUtil)); return commandManager; diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 934ca10c..dd2d8b5b 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -12,10 +12,10 @@ indra { dependencies { api(projects.core) - implementation("cloud.commandframework", "cloud-velocity", Versions.cloudVersion) + implementation("org.incendo", "cloud-velocity", Versions.cloudVersion) } -relocate("cloud.commandframework") +relocate("org.incendo.cloud") // used in cloud relocate("io.leangen.geantyref") diff --git a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java index fb412b47..91ced577 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java +++ b/velocity/src/main/java/org/geysermc/floodgate/module/VelocityPlatformModule.java @@ -25,17 +25,12 @@ package org.geysermc.floodgate.module; -import cloud.commandframework.CommandManager; -import cloud.commandframework.execution.CommandExecutionCoordinator; -import cloud.commandframework.velocity.CloudInjectionModule; -import cloud.commandframework.velocity.VelocityCommandManager; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.name.Named; -import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.proxy.ProxyServer; import lombok.RequiredArgsConstructor; @@ -51,6 +46,7 @@ import org.geysermc.floodgate.platform.util.PlatformUtils; import org.geysermc.floodgate.player.FloodgateCommandPreprocessor; import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.player.audience.FloodgateSenderMapper; import org.geysermc.floodgate.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.pluginmessage.PluginMessageRegistration; import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageRegistration; @@ -59,6 +55,10 @@ import org.geysermc.floodgate.util.VelocityCommandUtil; import org.geysermc.floodgate.util.VelocityPlatformUtils; import org.geysermc.floodgate.util.VelocitySkinApplier; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.velocity.CloudInjectionModule; +import org.incendo.cloud.velocity.VelocityCommandManager; @RequiredArgsConstructor public final class VelocityPlatformModule extends AbstractModule { @@ -77,9 +77,8 @@ protected void configure() { public CommandManager commandManager(CommandUtil commandUtil) { Injector child = guice.createChildInjector(new CloudInjectionModule<>( UserAudience.class, - CommandExecutionCoordinator.simpleCoordinator(), - commandUtil::getUserAudience, - audience -> (CommandSource) audience.source() + ExecutionCoordinator.simpleCoordinator(), + new FloodgateSenderMapper<>(commandUtil) )); CommandManager commandManager = From a44e3a5df8e3823e548c59d158f65cd7908a96b7 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 29 Apr 2024 08:28:46 +0200 Subject: [PATCH 096/113] Fixed an oversight that resulted in old versions not working --- .../main/java/org/geysermc/floodgate/util/ClassNames.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java index 9dbc1497..029b89b1 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java +++ b/spigot/src/main/java/org/geysermc/floodgate/util/ClassNames.java @@ -52,8 +52,6 @@ @SuppressWarnings("PMD.SystemPrintln") public class ClassNames { - public static final String SPIGOT_MAPPING_PREFIX; - public static final Class MINECRAFT_SERVER; public static final Class SERVER_CONNECTION; public static final Class HANDSHAKE_PACKET; @@ -108,7 +106,7 @@ public class ClassNames { // 'org.bukkit.craftbukkit. + version + CraftPlayer' will be .CraftPlayer on new // versions and .v1_8R3.CraftPlayer on older versions String version = versionSplit.length > 3 ? versionSplit[3] + '.' : ""; - SPIGOT_MAPPING_PREFIX = "net.minecraft.server." + version; + String nmsPackage = "net.minecraft.server." + version; // SpigotSkinApplier @@ -117,9 +115,6 @@ public class ClassNames { GET_PROFILE_METHOD = getMethod(craftPlayerClass, "getProfile"); checkNotNull(GET_PROFILE_METHOD, "Get profile method"); - String nmsPackage = SPIGOT_MAPPING_PREFIX + '.'; - - // SpigotInjector MINECRAFT_SERVER = getClassOrFallback( "net.minecraft.server.MinecraftServer", From 41c42ed3bb6cb4cc973a435f0dd3f68e84b982b0 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 6 May 2024 12:04:58 +0200 Subject: [PATCH 097/113] Update cloud (#505) --- build-logic/src/main/kotlin/Versions.kt | 3 ++- core/build.gradle.kts | 3 ++- .../floodgate/player/audience/PlayerAudienceArgument.java | 4 ++-- spigot/build.gradle.kts | 4 +--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 183655f4..406c8e1f 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -33,7 +33,8 @@ object Versions { const val guiceVersion = "6.0.0" const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" - const val cloudVersion = "2.0.0-beta.2" + // TODO move to cloud release once those have 1.20.5 support + const val cloudVersion = "2.0.0-20240503.183307-62" // for cloud-minecraft const val bstatsVersion = "3.0.2" const val javaWebsocketVersion = "1.5.2" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7d3d4632..e2e75259 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -15,7 +15,8 @@ dependencies { api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion) api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion) api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion) - api("org.incendo", "cloud-core", Versions.cloudVersion) + // TODO move to cloud release + api("org.incendo", "cloud-core", "2.0.0-20240503.181645-64") api("org.bstats", "bstats-base", Versions.bstatsVersion) } diff --git a/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java b/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java index 3829db3a..765fa75f 100644 --- a/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java +++ b/core/src/main/java/org/geysermc/floodgate/player/audience/PlayerAudienceArgument.java @@ -102,10 +102,10 @@ private static CommandComponent.Builder of(String CommandUtil commandUtil = context.get("CommandUtil"); boolean quoted = input.remainingInput().startsWith("\""); - List suggestions = new ArrayList(); + List suggestions = new ArrayList<>(); for (final String player : commandUtil.getOnlineUsernames(limitTo)) { suggestions.add( - Suggestion.simple(BrigadierUtils.escapeIfRequired(player, quoted))); + Suggestion.suggestion(BrigadierUtils.escapeIfRequired(player, quoted))); } return CompletableFuture.completedFuture(suggestions); }); diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index 193fc27e..6e95bae1 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -13,9 +13,7 @@ indra { dependencies { api(projects.core) - // TODO move to release once cloud-paper releases for 1.20.5 - // https://repo.papermc.io/#browse/browse:maven-public:org%2Fincendo%2Fcloud-paper%2F2.0.0-SNAPSHOT%2F2.0.0-20240427.220226-58 - implementation("org.incendo", "cloud-paper", "2.0.0-20240427.220226-58") + implementation("org.incendo", "cloud-paper", Versions.cloudVersion) // hack to make pre 1.12 work implementation("com.google.guava", "guava", guavaVersion) From 4404c15f1a0ae0c19ff3a763654f7a29b27c1d02 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 8 May 2024 17:15:44 +0200 Subject: [PATCH 098/113] Allow Floodgate-Fabric to provide it's own TemplateReader (#507) --- .../org/geysermc/floodgate/config/ConfigLoader.java | 5 +++-- .../org/geysermc/floodgate/module/CommonModule.java | 10 +++++++++- .../geysermc/floodgate/module/ServerCommonModule.java | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java index e4311058..739e1767 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/config/ConfigLoader.java @@ -33,7 +33,7 @@ import lombok.RequiredArgsConstructor; import org.geysermc.configutils.ConfigUtilities; import org.geysermc.configutils.file.codec.PathFileCodec; -import org.geysermc.configutils.file.template.ResourceTemplateReader; +import org.geysermc.configutils.file.template.TemplateReader; import org.geysermc.configutils.updater.change.Changes; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; @@ -46,6 +46,7 @@ public final class ConfigLoader { private final KeyProducer keyProducer; private final FloodgateCipher cipher; + private final TemplateReader reader; @SuppressWarnings("unchecked") public T load() { @@ -64,7 +65,7 @@ public T load() { ConfigUtilities.builder() .fileCodec(PathFileCodec.of(dataDirectory)) .configFile("config.yml") - .templateReader(ResourceTemplateReader.of(getClass())) + .templateReader(reader) .template(templateFile) .changes(Changes.builder() .version(1, Changes.versionBuilder() diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index 881f3ede..cddb93f7 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -40,6 +40,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import lombok.RequiredArgsConstructor; +import org.geysermc.configutils.file.template.ResourceTemplateReader; +import org.geysermc.configutils.file.template.TemplateReader; import org.geysermc.event.PostOrder; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.api.FloodgateApi; @@ -75,6 +77,12 @@ public class CommonModule extends AbstractModule { private final EventBus eventBus = new EventBus(); private final Path dataDirectory; + private final TemplateReader reader; + + public CommonModule(Path dataDirectory) { + this.dataDirectory = dataDirectory; + this.reader = ResourceTemplateReader.of(ConfigLoader.class); + } @Override protected void configure() { @@ -154,7 +162,7 @@ public ConfigLoader configLoader( @Named("configClass") Class configClass, KeyProducer producer, FloodgateCipher cipher) { - return new ConfigLoader(dataDirectory, configClass, producer, cipher); + return new ConfigLoader(dataDirectory, configClass, producer, cipher, reader); } @Provides diff --git a/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java index 23514824..9afb2253 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/ServerCommonModule.java @@ -29,6 +29,7 @@ import com.google.inject.Singleton; import com.google.inject.name.Named; import java.nio.file.Path; +import org.geysermc.configutils.file.template.TemplateReader; import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.config.FloodgateConfig; @@ -37,6 +38,11 @@ public ServerCommonModule(Path dataDirectory) { super(dataDirectory); } + // Used in floodgate-fabric to provide it's own reader implementation + public ServerCommonModule(Path dataDirectory, TemplateReader reader) { + super(dataDirectory, reader); + } + @Override protected void configure() { super.configure(); From f8c84182d618cfd450f585b17c94dbebfceac019 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 14 May 2024 17:41:00 +0200 Subject: [PATCH 099/113] Deal with getLocale being nullable during login on BungeeCord (#511) * Temporary fix for https://github.com/GeyserMC/Floodgate/issues/510, bump cloud to rc candidate * apparently it is supposed to be nullable. okay then. --- build-logic/src/main/kotlin/Versions.kt | 3 ++- .../java/org/geysermc/floodgate/util/BungeeCommandUtil.java | 4 +++- core/build.gradle.kts | 3 +-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 406c8e1f..d04e0f59 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -34,7 +34,8 @@ object Versions { const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" // TODO move to cloud release once those have 1.20.5 support - const val cloudVersion = "2.0.0-20240503.183307-62" // for cloud-minecraft + const val cloudVersion = "2.0.0-beta.7" // for cloud-minecraft + const val cloudCore = "2.0.0-rc.1" const val bstatsVersion = "3.0.2" const val javaWebsocketVersion = "1.5.2" diff --git a/bungee/src/main/java/org/geysermc/floodgate/util/BungeeCommandUtil.java b/bungee/src/main/java/org/geysermc/floodgate/util/BungeeCommandUtil.java index 8d1e7c1c..322a0332 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/util/BungeeCommandUtil.java +++ b/bungee/src/main/java/org/geysermc/floodgate/util/BungeeCommandUtil.java @@ -26,6 +26,7 @@ package org.geysermc.floodgate.util; import java.util.Collection; +import java.util.Locale; import java.util.UUID; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.ProxyServer; @@ -63,7 +64,8 @@ public BungeeCommandUtil(LanguageManager manager, ProxyServer server, FloodgateA ProxiedPlayer player = (ProxiedPlayer) source; UUID uuid = player.getUniqueId(); String username = player.getName(); - String locale = Utils.getLocale(player.getLocale()); + Locale playerLocale = player.getLocale(); // Is null during the PostLoginEvent, which can cause https://github.com/GeyserMC/Floodgate/issues/510 + String locale = Utils.getLocale(playerLocale != null ? playerLocale : Locale.getDefault()); return new PlayerAudience(uuid, username, locale, source, this, true); } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index e2e75259..20a9233c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -15,8 +15,7 @@ dependencies { api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion) api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion) api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion) - // TODO move to cloud release - api("org.incendo", "cloud-core", "2.0.0-20240503.181645-64") + api("org.incendo", "cloud-core", Versions.cloudCore) api("org.bstats", "bstats-base", Versions.bstatsVersion) } From 00b8b1b6364116ff4bc9b00e2015ce35bae8abb1 Mon Sep 17 00:00:00 2001 From: Bridge <29434554+bridgelol@users.noreply.github.com> Date: Sat, 18 May 2024 15:01:55 +0200 Subject: [PATCH 100/113] Reduce session server lookups (#509) * fix: add default skin to gameprofiles * fix: add signatures by default to prevent issues * cleanup * no longer apply empty textures * revert formatting change * fix(spigot): linked player textures * fix(velocity): linked player textures * fix(bungeecord): apply linked textures * Made the MojangUtils class instance based, removed some unneeded code * Don't block Velocity event threads, made the Bungee variant work * Add some comments --------- Co-authored-by: bridge Co-authored-by: Tim203 --- .../floodgate/listener/BungeeListener.java | 34 ++++-- .../pluginmessage/BungeeSkinApplier.java | 2 - .../geysermc/floodgate/skin/SkinDataImpl.java | 6 + .../geysermc/floodgate/util/MojangUtils.java | 110 ++++++++++++++++++ .../geysermc/floodgate/util/Constants.java | 6 + .../addon/data/SpigotDataHandler.java | 15 +++ .../listener/PaperProfileListener.java | 32 ++--- .../floodgate/listener/VelocityListener.java | 54 +++++++-- 8 files changed, 214 insertions(+), 45 deletions(-) create mode 100644 core/src/main/java/org/geysermc/floodgate/util/MojangUtils.java diff --git a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java index 9723cf58..f7e4b6fd 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java +++ b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java @@ -39,6 +39,7 @@ import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventPriority; @@ -46,10 +47,10 @@ import org.geysermc.floodgate.api.ProxyFloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; -import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.skin.SkinDataImpl; import org.geysermc.floodgate.util.LanguageManager; +import org.geysermc.floodgate.util.MojangUtils; import org.geysermc.floodgate.util.ReflectionUtils; @SuppressWarnings("ConstantConditions") @@ -66,7 +67,7 @@ public final class BungeeListener implements Listener { checkNotNull(PLAYER_NAME, "Initial name field cannot be null"); } - @Inject private ProxyFloodgateConfig config; + @Inject private Plugin plugin; @Inject private ProxyFloodgateApi api; @Inject private LanguageManager languageManager; @Inject private FloodgateLogger logger; @@ -80,6 +81,8 @@ public final class BungeeListener implements Listener { @Named("kickMessageAttribute") private AttributeKey kickMessageAttribute; + @Inject private MojangUtils mojangUtils; + @EventHandler(priority = EventPriority.LOWEST) public void onPreLogin(PreLoginEvent event) { // well, no reason to check if the player will be kicked anyway @@ -127,13 +130,28 @@ public void onLogin(LoginEvent event) { @EventHandler(priority = EventPriority.LOWEST) public void onPostLogin(PostLoginEvent event) { - // To fix the February 2 2022 Mojang authentication changes - if (!config.isSendFloodgateData()) { - FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); - if (player != null && !player.isLinked()) { - skinApplier.applySkin(player, new SkinDataImpl("", "")); - } + FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); + + // Skin look up (on Spigot and friends) would result in it failing, so apply a default skin + if (!player.isLinked()) { + skinApplier.applySkin(player, SkinDataImpl.DEFAULT_SKIN); + return; } + + // Floodgate players are seen as offline mode players, meaning we have to look up + // the linked player's textures ourselves + + event.registerIntent(plugin); + + mojangUtils.skinFor(player.getJavaUniqueId()) + .exceptionally(exception -> { + logger.debug("Unexpected skin fetch error for " + player.getJavaUniqueId(), exception); + return SkinDataImpl.DEFAULT_SKIN; + }) + .thenAccept(skin -> { + skinApplier.applySkin(player, skin); + event.completeIntent(plugin); + }); } @EventHandler(priority = EventPriority.HIGHEST) diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index ce6105ec..fa2aaad2 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -92,8 +92,6 @@ public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinDat SkinData currentSkin = currentSkin(properties); SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData); - event.setCancelled(floodgatePlayer.isLinked()); - eventBus.fire(event); if (event.isCancelled()) { diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java index 9f44af79..1e2247e2 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinDataImpl.java @@ -29,8 +29,14 @@ import java.util.Objects; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; +import org.geysermc.floodgate.util.Constants; public class SkinDataImpl implements SkinData { + public static final SkinData DEFAULT_SKIN = new SkinDataImpl( + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE, + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE + ); + private final String value; private final String signature; diff --git a/core/src/main/java/org/geysermc/floodgate/util/MojangUtils.java b/core/src/main/java/org/geysermc/floodgate/util/MojangUtils.java new file mode 100644 index 00000000..423ff44b --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/util/MojangUtils.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019-2024 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/Floodgate + */ + +package org.geysermc.floodgate.util; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import lombok.NonNull; +import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; +import org.geysermc.floodgate.skin.SkinDataImpl; +import org.geysermc.floodgate.util.HttpClient.HttpResponse; + +@Singleton +public class MojangUtils { + private final Cache SKIN_CACHE = CacheBuilder.newBuilder() + .expireAfterWrite(5, TimeUnit.MINUTES) + .maximumSize(500) + .build(); + + @Inject private HttpClient httpClient; + @Inject + @Named("commonPool") + private ExecutorService commonPool; + + public CompletableFuture<@NonNull SkinData> skinFor(UUID playerId) { + return CompletableFuture.supplyAsync(() -> { + try { + return SKIN_CACHE.get(playerId, () -> fetchSkinFor(playerId)); + } catch (ExecutionException exception) { + throw new RuntimeException(exception.getCause()); + } + }, commonPool); + } + + private @NonNull SkinData fetchSkinFor(UUID playerId) { + HttpResponse httpResponse = httpClient.get( + String.format(Constants.PROFILE_WITH_PROPERTIES_URL, playerId.toString())); + + if (httpResponse.getHttpCode() != 200) { + return SkinDataImpl.DEFAULT_SKIN; + } + + JsonObject response = httpResponse.getResponse(); + + if (response == null) { + return SkinDataImpl.DEFAULT_SKIN; + } + + JsonArray properties = response.getAsJsonArray("properties"); + + if (properties.size() == 0) { + return SkinDataImpl.DEFAULT_SKIN; + } + + for (JsonElement property : properties) { + if (!property.isJsonObject()) { + continue; + } + + JsonObject propertyObject = property.getAsJsonObject(); + + if (!propertyObject.has("name") + || !propertyObject.has("value") + || !propertyObject.has("signature") + || !propertyObject.get("name").getAsString().equals("textures")) { + continue; + } + + return new SkinDataImpl( + propertyObject.get("value").getAsString(), + propertyObject.get("signature").getAsString() + ); + } + + return SkinDataImpl.DEFAULT_SKIN; + } +} diff --git a/core/src/main/templates/org/geysermc/floodgate/util/Constants.java b/core/src/main/templates/org/geysermc/floodgate/util/Constants.java index 62cec467..1eec715a 100644 --- a/core/src/main/templates/org/geysermc/floodgate/util/Constants.java +++ b/core/src/main/templates/org/geysermc/floodgate/util/Constants.java @@ -56,6 +56,9 @@ public final class Constants { public static final String LATEST_VERSION_URL = "https://download.geysermc.org/v2/projects/%s/versions/latest/builds/latest"; + public static final String PROFILE_WITH_PROPERTIES_URL = + "https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false"; + public static final String NTP_SERVER = "time.cloudflare.com"; public static final String INTERNAL_ERROR_MESSAGE = @@ -70,4 +73,7 @@ public final class Constants { public static final int HANDSHAKE_PACKET_ID = 0; public static final int LOGIN_SUCCESS_PACKET_ID = 2; public static final int SET_COMPRESSION_PACKET_ID = 3; + + public static final String DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTcxNTcxNzM1NTI2MywKICAicHJvZmlsZUlkIiA6ICIyMWUzNjdkNzI1Y2Y0ZTNiYjI2OTJjNGEzMDBhNGRlYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJHZXlzZXJNQyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8zMWY0NzdlYjFhN2JlZWU2MzFjMmNhNjRkMDZmOGY2OGZhOTNhMzM4NmQwNDQ1MmFiMjdmNDNhY2RmMWI2MGNiIgogICAgfQogIH0KfQ"; + public static final String DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE = "dFKIZ5d6vNqCSe1IFGiVLjt3cnW8qh4qNP2umg9zqkX9bvAQawuR1iuO1kCD/+ye8A6GQFv2wRCdxdrjp5+Vrr0SsWqMnsYDN8cEg6CD18mAnaKI1TYDuGbdJaqLyGqN5wqSMdHxchs9iovFkde5ir4aYdvHkA11vOTi11L4kUzETGzJ4iKVuZOv4dq+B7wFAWqp4n8QZfhixyvemFazQHlLmxnuhU+jhpZMvYY9MAaRAJonfy/wJe9LymbTe0EJ8N+NwZQDrEUzgfBFo4OIGDqRZwvydInCqkjhPMtHCSL25VOKwcFocYpRYbk4eIKM4CLjYlBiQGki+XKsPaljwjVhnT0jUupSf7yraGb3T0CsVBjhDbIIIp9nytlbO0GvxHu0TzYjkr4Iji0do5jlCKQ/OasXcL21wd6ozw0t1QZnnzxi9ewSuyYVY9ErmWdkww1OtCIgJilceEBwNAB8+mhJ062WFaYPgJQAmOREM8InW33dbbeENMFhQi4LIO5P7p9ye3B4Lrwm20xtd9wJk3lewzcs8ezh0LUF6jPSDQDivgSKU49mLCTmOi+WZh8zKjjxfVEtNZON2W+3nct0LiWBVsQ55HzlvF0FFxuRVm6pxi6MQK2ernv3DQl0hUqyQ1+RV9nfZXTQOAUzwLjKx3t2zKqyZIiNEKLE+iAXrsE="; } diff --git a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java index 36f34e9d..383fa7e9 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java +++ b/spigot/src/main/java/org/geysermc/floodgate/addon/data/SpigotDataHandler.java @@ -29,6 +29,7 @@ import static org.geysermc.floodgate.util.ReflectionUtils.setValue; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; import io.netty.channel.Channel; import io.netty.util.AttributeKey; import java.lang.reflect.InvocationTargetException; @@ -38,9 +39,16 @@ import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult; import org.geysermc.floodgate.util.ClassNames; +import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.ProxyUtils; public final class SpigotDataHandler extends CommonDataHandler { + private static final Property DEFAULT_TEXTURE_PROPERTY = new Property( + "textures", + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE, + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE + ); + private Object networkManager; private FloodgatePlayer player; private boolean proxyData; @@ -171,6 +179,13 @@ private boolean checkAndHandleLogin(Object packet) throws Exception { player.getCorrectUniqueId(), player.getCorrectUsername() ); + if (!player.isLinked()) { + // Otherwise game server will try to fetch the skin from Mojang. + // No need to worry that this overrides proxy data, because those won't reach this + // method / are already removed (in the case of username validation) + gameProfile.getProperties().put("textures", DEFAULT_TEXTURE_PROPERTY); + } + // we have to fake the offline player (login) cycle if (ClassNames.IS_PRE_1_20_2) { diff --git a/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java b/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java index 29ade2ec..836b9fb2 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java +++ b/spigot/src/main/java/org/geysermc/floodgate/listener/PaperProfileListener.java @@ -26,20 +26,24 @@ package org.geysermc.floodgate.listener; import com.destroystokyo.paper.event.profile.PreFillProfileEvent; -import com.destroystokyo.paper.profile.PlayerProfile; import com.destroystokyo.paper.profile.ProfileProperty; import com.google.inject.Inject; import java.util.HashSet; import java.util.Set; import java.util.UUID; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import org.geysermc.floodgate.util.Constants; public final class PaperProfileListener implements Listener { + private static final ProfileProperty DEFAULT_TEXTURE_PROPERTY = new ProfileProperty( + "textures", + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE, + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE + ); + @Inject private SimpleFloodgateApi api; @EventHandler @@ -62,26 +66,8 @@ public void onFill(PreFillProfileEvent event) { } Set properties = new HashSet<>(event.getPlayerProfile().getProperties()); - properties.add(new ProfileProperty("textures", "", "")); - event.setProperties(properties); - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Player bukkitPlayer = event.getPlayer(); - FloodgatePlayer player = api.getPlayer(bukkitPlayer.getUniqueId()); - if (player == null || player.isLinked()) { - return; - } - - PlayerProfile profile = bukkitPlayer.getPlayerProfile(); - if (profile.getProperties().stream().noneMatch( - prop -> "textures".equals(prop.getName()) && prop.getValue().isEmpty() - && prop.getSignature() != null && prop.getSignature().isEmpty())) { - return; - } + properties.add(DEFAULT_TEXTURE_PROPERTY); - profile.removeProperty("textures"); - bukkitPlayer.setPlayerProfile(profile); + event.setProperties(properties); } } diff --git a/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java b/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java index 8000f520..82c7abcc 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java +++ b/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java @@ -36,6 +36,7 @@ import com.google.common.cache.CacheBuilder; import com.google.inject.Inject; import com.google.inject.name.Named; +import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; @@ -48,7 +49,7 @@ import io.netty.channel.Channel; import io.netty.util.AttributeKey; import java.lang.reflect.Field; -import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import net.kyori.adventure.text.Component; @@ -56,12 +57,16 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.config.ProxyFloodgateConfig; +import org.geysermc.floodgate.skin.SkinDataImpl; +import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.LanguageManager; +import org.geysermc.floodgate.util.MojangUtils; public final class VelocityListener { private static final Field INITIAL_MINECRAFT_CONNECTION; private static final Field INITIAL_CONNECTION_DELEGATE; private static final Field CHANNEL; + private static final Property DEFAULT_TEXTURE_PROPERTY; static { Class initialConnection = getPrefixedClass("connection.client.InitialInboundConnection"); @@ -82,6 +87,12 @@ public final class VelocityListener { } CHANNEL = getFieldOfType(minecraftConnection, Channel.class); + + DEFAULT_TEXTURE_PROPERTY = new Property( + "textures", + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE, + Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE + ); } private final Cache playerCache = @@ -103,6 +114,9 @@ public final class VelocityListener { @Named("kickMessageAttribute") private AttributeKey kickMessageAttribute; + @Inject + private MojangUtils mojangUtils; + @Subscribe(order = PostOrder.EARLY) public void onPreLogin(PreLoginEvent event) { FloodgatePlayer player = null; @@ -139,22 +153,38 @@ public void onPreLogin(PreLoginEvent event) { } @Subscribe(order = PostOrder.EARLY) - public void onGameProfileRequest(GameProfileRequestEvent event) { + public void onGameProfileRequest(GameProfileRequestEvent event, Continuation continuation) { FloodgatePlayer player = playerCache.getIfPresent(event.getConnection()); - if (player != null) { - playerCache.invalidate(event.getConnection()); + if (player == null) { + return; + } + playerCache.invalidate(event.getConnection()); - GameProfile profile = new GameProfile( + // Skin look up (on Spigot and friends) would result in it failing, so apply a default skin + if (!player.isLinked()) { + event.setGameProfile(new GameProfile( player.getCorrectUniqueId(), player.getCorrectUsername(), - Collections.emptyList() - ); - // The texture properties addition is to fix the February 2 2022 Mojang authentication changes - if (!config.isSendFloodgateData() && !player.isLinked()) { - profile = profile.addProperty(new Property("textures", "", "")); - } - event.setGameProfile(profile); + List.of(DEFAULT_TEXTURE_PROPERTY) + )); + return; } + + // Floodgate players are seen as offline mode players, meaning we have to look up + // the linked player's textures ourselves + + mojangUtils.skinFor(player.getJavaUniqueId()) + .exceptionally(exception -> { + logger.debug("Unexpected skin fetch error for " + player.getJavaUniqueId(), exception); + return SkinDataImpl.DEFAULT_SKIN; + }).thenAccept(skin -> { + event.setGameProfile(new GameProfile( + player.getCorrectUniqueId(), + player.getCorrectUsername(), + List.of(new Property("textures", skin.value(), skin.signature())) + )); + continuation.resume(); + }); } @Subscribe(order = PostOrder.LAST) From f1c52b48fc007a9aaeaa0a8d34da5f54ab1854f2 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 18 May 2024 17:43:33 +0200 Subject: [PATCH 101/113] Fixed recession in latest commit --- .../java/org/geysermc/floodgate/listener/VelocityListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java b/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java index 82c7abcc..cd625957 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java +++ b/velocity/src/main/java/org/geysermc/floodgate/listener/VelocityListener.java @@ -156,6 +156,7 @@ public void onPreLogin(PreLoginEvent event) { public void onGameProfileRequest(GameProfileRequestEvent event, Continuation continuation) { FloodgatePlayer player = playerCache.getIfPresent(event.getConnection()); if (player == null) { + continuation.resume(); return; } playerCache.invalidate(event.getConnection()); @@ -167,6 +168,7 @@ public void onGameProfileRequest(GameProfileRequestEvent event, Continuation con player.getCorrectUsername(), List.of(DEFAULT_TEXTURE_PROPERTY) )); + continuation.resume(); return; } From 792af7b0ddcd178fdaf9c5e5413920d491c88529 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 19 May 2024 00:10:17 +0200 Subject: [PATCH 102/113] Fixed bug in Bungee platform --- .../java/org/geysermc/floodgate/listener/BungeeListener.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java index f7e4b6fd..fd1befb6 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java +++ b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java @@ -131,6 +131,9 @@ public void onLogin(LoginEvent event) { @EventHandler(priority = EventPriority.LOWEST) public void onPostLogin(PostLoginEvent event) { FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); + if (player == null) { + return; + } // Skin look up (on Spigot and friends) would result in it failing, so apply a default skin if (!player.isLinked()) { From c4a44879b87c53818aba0a3e4327023d2be668de Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Mon, 27 May 2024 11:15:11 -0700 Subject: [PATCH 103/113] Switch to centralized GitHub actions (#516) * Switch to centralized GitHub actions * Build number is in env for PR --- .github/workflows/build.yml | 103 +++++++++++++----------------- .github/workflows/pullrequest.yml | 22 ++++--- 2 files changed, 56 insertions(+), 69 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66cb9840..c251f4a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,42 +5,44 @@ on: [push] jobs: build: runs-on: ubuntu-latest - env: - PROJECT: 'floodgate' steps: - - name: Set Build Number - env: - BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }} - run: | - BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1') - echo "BUILD_NUMBER=${BUILD_NUMBER:=$GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + - name: Get Release Info + id: release-info + uses: GeyserMC/actions/previous-release@master + with: + data: ${{ vars.RELEASEACTION_PREVRELEASE }} - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive - name: Validate Gradle Wrapper # See https://github.com/gradle/wrapper-validation-action/commits - uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 + uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + - name: Setup Java # See https://github.com/actions/setup-java/commits - - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: java-version: 17 distribution: temurin - - name: Build + - name: Setup Gradle # See https://github.com/gradle/actions/commits uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 with: - arguments: build cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }} + + - name: Build Floodgate + run: ./gradlew build + env: + BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} - name: Archive artifacts (Floodgate Bungee) # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: success() with: name: Floodgate Bungee @@ -48,8 +50,7 @@ jobs: if-no-files-found: error - name: Archive artifacts (Floodgate Spigot) - # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Floodgate Spigot @@ -57,8 +58,7 @@ jobs: if-no-files-found: error - name: Archive artifacts (Floodgate Velocity) - # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Floodgate Velocity @@ -67,18 +67,23 @@ jobs: - name: Publish to Maven Repository if: ${{ github.repository == 'GeyserMC/Floodgate' }} - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 + run: ./gradlew publish env: + BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} - with: - arguments: publish - cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }} + + - name: Get Version + if: ${{ success() && github.repository == 'GeyserMC/Floodgate' && github.ref_name == 'master' }} + id: get-version + run: | + version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + echo "VERSION=${version}" >> $GITHUB_OUTPUT - name: Get Release Metadata if: ${{ success() && github.repository == 'GeyserMC/Floodgate' && github.ref_name == 'master' }} - # See https://github.com/Kas-tle/base-release-action/releases/tag/main-11 - uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # main-11 + uses: GeyserMC/actions/release@master + id: metadata with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} @@ -88,45 +93,25 @@ jobs: velocity:velocity/build/libs/floodgate-velocity.jar releaseEnabled: false saveMetadata: true - - - name: Update Generated Metadata - if: ${{ success() && github.repository == 'GeyserMC/Floodgate' && github.ref_name == 'master' }} - run: | - cat metadata.json - echo - mv metadata.json metadata.json.tmp - version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) - jq --arg project "${PROJECT}" --arg version "${version}" ' - . - | .changes |= map({"commit", "summary", "message"}) - | .downloads |= map_values({"name", "sha256"}) - | {$project, "repo", $version, "number": .build, "changes", "downloads"} - ' metadata.json.tmp > metadata.json - cat metadata.json + releaseProject: 'floodgate' + releaseVersion: ${{ steps.get-version.outputs.VERSION }} - name: Publish to Downloads API if: ${{ success() && github.ref_name == 'master' && github.repository == 'GeyserMC/Floodgate' }} - shell: bash - env: - DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} - DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} - DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} - run: | - # Save the private key to a file - echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa - chmod 600 id_ecdsa - # Create the build folder - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/" - # Copy over artifacts - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bungee/build/libs/floodgate-bungee.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" spigot/build/libs/floodgate-spigot.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" velocity/build/libs/floodgate-velocity.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - # Run the build script - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ + uses: GeyserMC/actions/upload-release@master + with: + username: ${{ vars.DOWNLOADS_USERNAME }} + privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} + host: ${{ secrets.DOWNLOADS_SERVER_IP }} + files: | + bungee/build/libs/floodgate-bungee.jar + spigot/build/libs/floodgate-spigot.jar + velocity/build/libs/floodgate-velocity.jar - name: Notify Discord if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Floodgate' }} - # See https://github.com/Tim203/actions-git-discord-webhook/commits - uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff + uses: GeyserMC/actions/notify-discord@master with: - webhook_url: ${{ secrets.DISCORD_WEBHOOK }} + discordWebhook: ${{ secrets.DISCORD_WEBHOOK }} + status: ${{ job.status }} + body: ${{ steps.metadata.outputs.body }} diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 1b64603f..8d59fecf 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -14,31 +14,33 @@ jobs: - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive - name: Validate Gradle Wrapper # See https://github.com/gradle/wrapper-validation-action/commits - uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 + uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - - name: Set up JDK 17 + - name: Setup Java # See https://github.com/actions/setup-java/commits - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: java-version: 17 distribution: temurin - - name: Build Floodgate + - name: Setup Gradle # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 with: - arguments: build cache-read-only: true + - name: Build Floodgate + run: ./gradlew build + - name: Archive artifacts (Floodgate Bungee) # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: success() with: name: Floodgate Bungee @@ -46,7 +48,7 @@ jobs: if-no-files-found: error - name: Archive artifacts (Floodgate Spigot) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Floodgate Spigot @@ -54,7 +56,7 @@ jobs: if-no-files-found: error - name: Archive artifacts (Floodgate Velocity) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Floodgate Velocity From e1bae5765bc447e646bd21474216b4a53d73666e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 13 Jun 2024 18:01:39 -0400 Subject: [PATCH 104/113] Do not swallow errors on Spigot --- .../org/geysermc/floodgate/SpigotPlugin.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java index 2a5af4ee..a12c41a8 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java +++ b/spigot/src/main/java/org/geysermc/floodgate/SpigotPlugin.java @@ -67,17 +67,12 @@ public void onEnable() { boolean usePaperListener = ReflectionUtils.getClassSilently( "com.destroystokyo.paper.event.profile.PreFillProfileEvent") != null; - try { - platform.enable( - new SpigotCommandModule(this), - new SpigotAddonModule(), - new PluginMessageModule(), - (usePaperListener ? new PaperListenerModule() : new SpigotListenerModule()) - ); - } catch (Exception exception) { - Bukkit.getPluginManager().disablePlugin(this); - throw exception; - } + platform.enable( + new SpigotCommandModule(this), + new SpigotAddonModule(), + new PluginMessageModule(), + (usePaperListener ? new PaperListenerModule() : new SpigotListenerModule()) + ); injector.getInstance(HandshakeHandlers.class) .addHandshakeHandler(injector.getInstance(SpigotHandshakeHandler.class)); From 49bd56446fa10931b1c4abf6609055571a4ae105 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 14 Jun 2024 04:08:27 +0200 Subject: [PATCH 105/113] Preliminary 1.21 Spigot support (#521) --- build-logic/src/main/kotlin/Versions.kt | 3 +-- spigot/build.gradle.kts | 4 +++- .../org/geysermc/floodgate/module/SpigotCommandModule.java | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index d04e0f59..f22b3d80 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -33,8 +33,7 @@ object Versions { const val guiceVersion = "6.0.0" const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" - // TODO move to cloud release once those have 1.20.5 support - const val cloudVersion = "2.0.0-beta.7" // for cloud-minecraft + const val cloudVersion = "2.0.0-SNAPSHOT" // for cloud-minecraft const val cloudCore = "2.0.0-rc.1" const val bstatsVersion = "3.0.2" diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index 6e95bae1..af449d2f 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -13,7 +13,9 @@ indra { dependencies { api(projects.core) - implementation("org.incendo", "cloud-paper", Versions.cloudVersion) + //implementation("org.incendo", "cloud-paper", Versions.cloudVersion) + // TODO change back after https://github.com/incendo/cloud-minecraft is merged + implementation("com.github.onebeastchris.cloud-minecraft", "cloud-paper", "jitpack-SNAPSHOT") // hack to make pre 1.12 work implementation("com.google.guava", "guava", guavaVersion) diff --git a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java index 959c4ac0..d616181e 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java +++ b/spigot/src/main/java/org/geysermc/floodgate/module/SpigotCommandModule.java @@ -40,7 +40,7 @@ import org.geysermc.floodgate.player.audience.FloodgateSenderMapper; import org.incendo.cloud.CommandManager; import org.incendo.cloud.execution.ExecutionCoordinator; -import org.incendo.cloud.paper.PaperCommandManager; +import org.incendo.cloud.paper.LegacyPaperCommandManager; @RequiredArgsConstructor public final class SpigotCommandModule extends CommandModule { @@ -56,7 +56,7 @@ protected void configure() { @Singleton @SneakyThrows public CommandManager commandManager(CommandUtil commandUtil) { - CommandManager commandManager = new PaperCommandManager<>( + CommandManager commandManager = new LegacyPaperCommandManager<>( plugin, ExecutionCoordinator.simpleCoordinator(), new FloodgateSenderMapper<>(commandUtil) From e7e40f59bae71d37952a3edb50887b0dabe5525b Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 1 Sep 2024 20:45:10 +0200 Subject: [PATCH 106/113] Deprecate all the API classes that will be removed in Floodgate 3.0 See #536 for more information --- .../floodgate/api/InstanceHolder.java | 33 +++++++++++++++++-- .../api/handshake/HandshakeData.java | 7 ++-- .../api/handshake/HandshakeHandler.java | 9 ++--- .../api/handshake/HandshakeHandlers.java | 6 ++-- .../floodgate/api/inject/InjectorAddon.java | 5 +++ .../api/inject/PlatformInjector.java | 8 ++--- .../floodgate/api/packet/PacketHandler.java | 4 ++- .../floodgate/api/packet/PacketHandlers.java | 5 +++ 8 files changed, 52 insertions(+), 25 deletions(-) diff --git a/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java b/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java index 159310ee..e9730b10 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java +++ b/api/src/main/java/org/geysermc/floodgate/api/InstanceHolder.java @@ -38,9 +38,9 @@ public final class InstanceHolder { @Getter private static PlayerLink playerLink; @Getter private static FloodgateEventBus eventBus; - @Getter private static PlatformInjector injector; - @Getter private static PacketHandlers packetHandlers; - @Getter private static HandshakeHandlers handshakeHandlers; + private static PlatformInjector injector; + private static PacketHandlers packetHandlers; + private static HandshakeHandlers handshakeHandlers; private static UUID storedKey; public static boolean set( @@ -68,4 +68,31 @@ public static boolean set( InstanceHolder.handshakeHandlers = handshakeHandlers; return true; } + + /** + * @deprecated Injector addons will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. + */ + @Deprecated + public static PlatformInjector getInjector() { + return InstanceHolder.injector; + } + + /** + * @deprecated Packet handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. + */ + @Deprecated + public static PacketHandlers getPacketHandlers() { + return InstanceHolder.packetHandlers; + } + + /** + * @deprecated Handshake handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. + */ + @Deprecated + public static HandshakeHandlers getHandshakeHandlers() { + return InstanceHolder.handshakeHandlers; + } } diff --git a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java index 1ebc6525..9c1569a6 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java +++ b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeData.java @@ -31,11 +31,8 @@ import org.geysermc.floodgate.util.LinkedPlayer; /** - * For advanced users only! You shouldn't play with this unless you know what you're doing.
- *
- * This class allows you change specific things of a Bedrock player before it is applied to the - * server. Note that at the time I'm writing this that the HandshakeData is created after requesting - * the player link. So the link is present here, if applicable. + * @deprecated Handshake handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. */ @Deprecated public interface HandshakeData { diff --git a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java index 8ce06253..cab9ef93 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java +++ b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandler.java @@ -26,13 +26,8 @@ package org.geysermc.floodgate.api.handshake; /** - * This class allows you to change and/or get specific data of the Bedrock client before Floodgate - * does something with this data. This means that Floodgate decrypts the data, then calls the - * handshake handlers and then applies the data to the connection.
- *
- * /!\ Note that this class will be called for both Java and Bedrock connections, but {@link - * HandshakeData#isFloodgatePlayer()} will be false and Floodgate related methods will return null - * for Java players + * @deprecated Handshake handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. */ @Deprecated @FunctionalInterface diff --git a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java index 088ac9af..2d69a1ea 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java +++ b/api/src/main/java/org/geysermc/floodgate/api/handshake/HandshakeHandlers.java @@ -26,10 +26,8 @@ package org.geysermc.floodgate.api.handshake; /** - * @deprecated This system has been deprecated and will not be available in the new API that will be - * introduced when Geyser will include Floodgate (and thus will have some common base API). - *
- * It might be replaced with an event (probably internal), but that isn't certain yet. + * @deprecated Handshake handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. */ @Deprecated public interface HandshakeHandlers { diff --git a/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java b/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java index ee991b78..01fbc3cd 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java +++ b/api/src/main/java/org/geysermc/floodgate/api/inject/InjectorAddon.java @@ -27,6 +27,11 @@ import io.netty.channel.Channel; +/** + * @deprecated Injector addons will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. + */ +@Deprecated public interface InjectorAddon { /** * Called when injecting a specific channel (every client that is connected to the server has diff --git a/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java b/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java index 4c28ac40..026fb08a 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java +++ b/api/src/main/java/org/geysermc/floodgate/api/inject/PlatformInjector.java @@ -26,12 +26,10 @@ package org.geysermc.floodgate.api.inject; /** - * The global interface of all the Platform Injectors. The injector can be used for various things. - * It is used internally for getting Floodgate data out of the handshake packet and for debug mode, - * but there is also an option to add your own addons. Note that every Floodgate platform that - * supports netty should implement this, but the platform implementation isn't required to implement - * this. + * @deprecated Injector addons will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. */ +@Deprecated public interface PlatformInjector { /** * Injects the server connection. This will allow various addons (like getting the Floodgate diff --git a/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java b/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java index 3170175c..1ddb9cf3 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java +++ b/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandler.java @@ -28,8 +28,10 @@ import io.netty.channel.ChannelHandlerContext; /** - * For advanced users only! You shouldn't play with this unless you know what you're doing. + * @deprecated Packet handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. */ +@Deprecated public interface PacketHandler { /** * Called when a registered packet has been seen. diff --git a/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java b/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java index e59c66fc..083b16c4 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java +++ b/api/src/main/java/org/geysermc/floodgate/api/packet/PacketHandlers.java @@ -28,6 +28,11 @@ import io.netty.channel.ChannelHandlerContext; import org.geysermc.floodgate.api.util.TriFunction; +/** + * @deprecated Packet handlers will be removed with the launch of Floodgate 3.0. Please look at + * #536 for additional context. + */ +@Deprecated public interface PacketHandlers { /** * Register a specific class for a specific consumer. From 3db8e5931f8def161174a69c90553be6a9a0fb46 Mon Sep 17 00:00:00 2001 From: Outfluencer Date: Sat, 14 Sep 2024 22:05:04 +0200 Subject: [PATCH 107/113] Support latest BungeeCord changes (#546) * update bungee injector * add backwards compatibility --- .../inject/bungee/BungeeInjector.java | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index ac39d4d0..53e56b67 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -28,9 +28,11 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; import java.lang.reflect.Field; +import java.lang.reflect.Method; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.md_5.bungee.netty.PipelineUtils; @@ -52,8 +54,10 @@ public final class BungeeInjector extends CommonPlatformInjector { @Override public void inject() { // Can everyone just switch to Velocity please :) + // :( ~BungeeCord Collaborator // Newer Bungee versions have a separate prepender for backend and client connections + // this field is not touched by client -> proxy Field serverFramePrepender = ReflectionUtils.getField(PipelineUtils.class, "serverFramePrepender"); if (serverFramePrepender != null) { @@ -63,16 +67,39 @@ public void inject() { BungeeReflectionUtils.setFieldValue(null, serverFramePrepender, customServerPrepender); } + // for backwards compatibility Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); + if (framePrepender != null) { + logger.warn("You are running an old version of BungeeCord consider updating to a newer version"); + // Required in order to inject into both Geyser <-> proxy AND proxy <-> server + // (Instead of just replacing the ChannelInitializer which is only called for + // player <-> proxy) + BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( + this, ReflectionUtils.castedStaticValue(framePrepender) + ); - // Required in order to inject into both Geyser <-> proxy AND proxy <-> server - // (Instead of just replacing the ChannelInitializer which is only called for - // player <-> proxy) - BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( - this, ReflectionUtils.castedStaticValue(framePrepender) - ); - - BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender); + BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender); + } else { + // wrap the client -> proxy channel init because the framePrepender field was deleted + ChannelInitializer original = PipelineUtils.SERVER_CHILD; + Field clientChannelInitField = ReflectionUtils.getField( + PipelineUtils.class, "SERVER_CHILD" + ); + Method initChannelMethod = ReflectionUtils.getMethod( + original.getClass(), "initChannel", Channel.class + ); + ChannelInitializer wrapper = new ChannelInitializer() { + @Override + protected void initChannel(Channel channel) { + ReflectionUtils.invoke(original, initChannelMethod, channel); + channel.pipeline().addBefore( + PipelineUtils.FRAME_DECODER, BUNGEE_INIT, + new BungeeClientToProxyInjectInitializer(BungeeInjector.this) + ); + } + }; + BungeeReflectionUtils.setFieldValue(null, clientChannelInitField, wrapper); + } injected = true; } From 0360721d9c7bd9376e368ed98c412439a6bc460f Mon Sep 17 00:00:00 2001 From: LinsaFTW <25271111+linsaftw@users.noreply.github.com> Date: Sun, 29 Sep 2024 07:32:56 -0300 Subject: [PATCH 108/113] Check if channel is open before injecting (#547) * Check if channel is open before injecting Some forks like FlameCord have integrated anti-bot features to block connections early. By default, Floodgate runs anyways, which not only makes bot attacks affect the server when Floodgate is instaled, but also generate an exception. This fixes the issue. * Add note about why it's added --------- Co-authored-by: Tim203 --- .../org/geysermc/floodgate/inject/bungee/BungeeInjector.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index 53e56b67..21967142 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -91,6 +91,10 @@ public void inject() { ChannelInitializer wrapper = new ChannelInitializer() { @Override protected void initChannel(Channel channel) { + // Check if the channel is open, see #547 + if (!channel.isOpen()) { + return; + } ReflectionUtils.invoke(original, initChannelMethod, channel); channel.pipeline().addBefore( PipelineUtils.FRAME_DECODER, BUNGEE_INIT, From 06f2ed966ed82ea20b70757137d84a904ce177a8 Mon Sep 17 00:00:00 2001 From: LittleShyStar02 Date: Thu, 31 Oct 2024 16:44:27 +0100 Subject: [PATCH 109/113] Actually check if the channel is open, fixes #547 (#557) * Moved check of channel open of #547. In previous point was always true and it did not solve problem. * Moved check of channel open of #547. In previous point was always true and it did not solve problem. * Make the comment more compact --------- Co-authored-by: Tim203 --- .../org/geysermc/floodgate/inject/bungee/BungeeInjector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index 21967142..f58c8001 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -91,11 +91,12 @@ public void inject() { ChannelInitializer wrapper = new ChannelInitializer() { @Override protected void initChannel(Channel channel) { + ReflectionUtils.invoke(original, initChannelMethod, channel); // Check if the channel is open, see #547 if (!channel.isOpen()) { return; } - ReflectionUtils.invoke(original, initChannelMethod, channel); + channel.pipeline().addBefore( PipelineUtils.FRAME_DECODER, BUNGEE_INIT, new BungeeClientToProxyInjectInitializer(BungeeInjector.this) From 83fbd6edbd7e179397d00a31119c9fad2e3a6d41 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:51:49 -0800 Subject: [PATCH 110/113] Update README.md Download, Status, and Wiki Links (#559) * Update README.md * Correct CI link --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 652325ce..9b8e6600 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # Floodgate [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Build Status](https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/) +[![Build Status](https://github.com/GeyserMC/Floodgate/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/GeyserMC/Floodgate/actions/workflows/build.yml?query=branch%3Amaster) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) [![HitCount](https://hits.dwyl.com/GeyserMC/Floodgate.svg)](http://hits.dwyl.com/GeyserMC/Floodgate) -[Download](https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/) +[Download](https://geysermc.org/download/?project=floodgate) Hybrid mode plugin to allow for connections from [Geyser](https://github.com/GeyserMC/Geyser) to join online mode servers. Geyser is an open collaboration project by [CubeCraft Games](https://cubecraft.net). -See the [Floodgate](https://wiki.geysermc.org/floodgate/) section in the GeyserMC Wiki for more info about what Floodgate is, how you setup Floodgate and known issues/caveats. Additionally, it includes a more in-depth look into how Floodgate works and the Floodgate API. +See the [Floodgate](https://geysermc.org/wiki/floodgate/) section in the GeyserMC Wiki for more info about what Floodgate is, how you setup Floodgate and known issues/caveats. Additionally, it includes a more in-depth look into how Floodgate works and the Floodgate API. From 2deccf314413f63f7150ff5ca70af501ffc11430 Mon Sep 17 00:00:00 2001 From: Roch Blondiaux <68775690+RochBlondiaux@users.noreply.github.com> Date: Tue, 11 Feb 2025 20:11:25 +0100 Subject: [PATCH 111/113] Implemented a way to close forms from floodgate (#566) * feat: added #closeForm method to FloodgateApi * feat: implementation of the closeForm method * Update Floodgate API version --------- Co-authored-by: Roch Blonndiaux Co-authored-by: onebeastchris --- .../main/java/org/geysermc/floodgate/api/FloodgateApi.java | 2 ++ .../java/org/geysermc/floodgate/api/SimpleFloodgateApi.java | 5 +++++ .../floodgate/pluginmessage/channel/FormChannel.java | 4 ++++ gradle.properties | 2 +- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java index 999935ab..a51252a3 100644 --- a/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java +++ b/api/src/main/java/org/geysermc/floodgate/api/FloodgateApi.java @@ -97,6 +97,8 @@ static FloodgateApi getInstance() { boolean sendForm(UUID uuid, FormBuilder formBuilder); + boolean closeForm(UUID uuid); + /** * @deprecated since Cumulus 1.1 and will be removed when Cumulus 2.0 releases. Please use the * new form classes instead. diff --git a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java index 5ef49e46..baf05da8 100644 --- a/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/api/SimpleFloodgateApi.java @@ -125,6 +125,11 @@ public boolean sendForm(UUID uuid, FormBuilder formBuilder) { return sendForm(uuid, formBuilder.build()); } + @Override + public boolean closeForm(UUID uuid) { + return pluginMessageManager.getChannel(FormChannel.class).closeForm(uuid); + } + @Override public boolean sendForm(UUID uuid, org.geysermc.cumulus.Form form) { return sendForm(uuid, form.newForm()); diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java index 1da89bc1..187d0edc 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/FormChannel.java @@ -93,6 +93,10 @@ public Result handleServerCall(byte[] data, UUID playerUuid, String playerUserna return Result.handled(); } + public boolean closeForm(UUID player) { + return pluginMessageUtils.sendMessage(player, getIdentifier(), new byte[0]); + } + public boolean sendForm(UUID player, Form form) { byte[] formData = createFormData(form); return pluginMessageUtils.sendMessage(player, getIdentifier(), formData); diff --git a/gradle.properties b/gradle.properties index 8e836211..69e11adc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ org.gradle.configureondemand=true org.gradle.caching=true org.gradle.parallel=true -version=2.2.3-SNAPSHOT \ No newline at end of file +version=2.2.4-SNAPSHOT \ No newline at end of file From 0e3163c94220cdc516d1d1219557376c5216312b Mon Sep 17 00:00:00 2001 From: Outfluencer Date: Sun, 16 Feb 2025 15:36:11 +0100 Subject: [PATCH 112/113] Use newly added BungeeCord ChannelInitializer API (#575) * Update BungeeInjector.java * Update bungee version * Add a message when running an outdated Bungee version --- bungee/build.gradle.kts | 2 +- .../inject/bungee/BungeeInjector.java | 178 +++--------------- 2 files changed, 28 insertions(+), 152 deletions(-) diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index 69ab1120..711d7a71 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -1,4 +1,4 @@ -var bungeeVersion = "1.20-R0.3-SNAPSHOT" +var bungeeVersion = "1.21-R0.1-SNAPSHOT" var gsonVersion = "2.8.0" var guavaVersion = "21.0" diff --git a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java index f58c8001..ed672f85 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java +++ b/bungee/src/main/java/org/geysermc/floodgate/inject/bungee/BungeeInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 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 @@ -26,86 +26,46 @@ package org.geysermc.floodgate.inject.bungee; import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOutboundHandlerAdapter; -import io.netty.channel.ChannelPromise; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.md_5.bungee.netty.PipelineUtils; -import net.md_5.bungee.protocol.MinecraftEncoder; -import net.md_5.bungee.protocol.Varint21LengthFieldExtraBufPrepender; -import net.md_5.bungee.protocol.Varint21LengthFieldPrepender; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.ProxyServer.Unsafe; +import net.md_5.bungee.protocol.channel.BungeeChannelInitializer; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.inject.CommonPlatformInjector; -import org.geysermc.floodgate.util.BungeeReflectionUtils; -import org.geysermc.floodgate.util.ReflectionUtils; @RequiredArgsConstructor public final class BungeeInjector extends CommonPlatformInjector { - private static final String BUNGEE_INIT = "floodgate-bungee-init"; - private final FloodgateLogger logger; @Getter private boolean injected; @Override public void inject() { - // Can everyone just switch to Velocity please :) - // :( ~BungeeCord Collaborator - - // Newer Bungee versions have a separate prepender for backend and client connections - // this field is not touched by client -> proxy - Field serverFramePrepender = - ReflectionUtils.getField(PipelineUtils.class, "serverFramePrepender"); - if (serverFramePrepender != null) { - BungeeCustomServerPrepender customServerPrepender = new BungeeCustomServerPrepender( - this, ReflectionUtils.castedStaticValue(serverFramePrepender) - ); - BungeeReflectionUtils.setFieldValue(null, serverFramePrepender, customServerPrepender); - } - - // for backwards compatibility - Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); - if (framePrepender != null) { - logger.warn("You are running an old version of BungeeCord consider updating to a newer version"); - // Required in order to inject into both Geyser <-> proxy AND proxy <-> server - // (Instead of just replacing the ChannelInitializer which is only called for - // player <-> proxy) - BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( - this, ReflectionUtils.castedStaticValue(framePrepender) - ); - - BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender); - } else { - // wrap the client -> proxy channel init because the framePrepender field was deleted - ChannelInitializer original = PipelineUtils.SERVER_CHILD; - Field clientChannelInitField = ReflectionUtils.getField( - PipelineUtils.class, "SERVER_CHILD" - ); - Method initChannelMethod = ReflectionUtils.getMethod( - original.getClass(), "initChannel", Channel.class - ); - ChannelInitializer wrapper = new ChannelInitializer() { - @Override - protected void initChannel(Channel channel) { - ReflectionUtils.invoke(original, initChannelMethod, channel); - // Check if the channel is open, see #547 - if (!channel.isOpen()) { - return; - } - - channel.pipeline().addBefore( - PipelineUtils.FRAME_DECODER, BUNGEE_INIT, - new BungeeClientToProxyInjectInitializer(BungeeInjector.this) - ); - } - }; - BungeeReflectionUtils.setFieldValue(null, clientChannelInitField, wrapper); + try { + ProxyServer.getInstance().unsafe(); + } catch (NoSuchMethodError ignored) { + logger.error("You're running an outdated version of BungeeCord. Please update BungeeCord to the latest version!"); + throw new Error("You're running an outdated version of BungeeCord. Please update BungeeCord to the latest version!"); } + Unsafe unsafe = ProxyServer.getInstance().unsafe(); + BungeeChannelInitializer frontend = unsafe.getFrontendChannelInitializer(); + unsafe.setFrontendChannelInitializer(BungeeChannelInitializer.create(channel -> { + if (!frontend.getChannelAcceptor().accept(channel)) { + return false; + } + injectClient(channel, true); + return true; + })); + + BungeeChannelInitializer backend = unsafe.getBackendChannelInitializer(); + unsafe.setBackendChannelInitializer(BungeeChannelInitializer.create(channel -> { + if (!backend.getChannelAcceptor().accept(channel)) { + return false; + } + injectClient(channel, false); + return true; + })); injected = true; } @@ -121,91 +81,7 @@ public void removeInjection() { } void injectClient(Channel channel, boolean clientToProxy) { - if (!channel.isOpen()) { - return; - } - - if (channel.pipeline().get(MinecraftEncoder.class) == null) { - logger.debug( - "Minecraft encoder not found while injecting! {}", - String.join(", ", channel.pipeline().names()) - ); - return; - } - injectAddonsCall(channel, !clientToProxy); addInjectedClient(channel); } - - @RequiredArgsConstructor - private static final class BungeeCustomPrepender extends Varint21LengthFieldPrepender { - private final BungeeInjector injector; - private final Varint21LengthFieldPrepender original; - - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - original.handlerAdded(ctx); - // The Minecraft encoder being in the pipeline isn't present until later - - if (ctx.channel().parent() != null) { - // Client <-> Proxy - ctx.pipeline().addBefore( - PipelineUtils.FRAME_DECODER, BUNGEE_INIT, - new BungeeClientToProxyInjectInitializer(injector) - ); - } else { - // Proxy <-> Server - ctx.pipeline().addLast( - BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector) - ); - } - } - } - - @RequiredArgsConstructor - private static final class BungeeCustomServerPrepender - extends Varint21LengthFieldExtraBufPrepender { - private final BungeeInjector injector; - private final Varint21LengthFieldExtraBufPrepender original; - - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - original.handlerAdded(ctx); - // The Minecraft encoder being in the pipeline isn't present until later - - // Proxy <-> Server - ctx.pipeline().addLast(BUNGEE_INIT, new BungeeProxyToServerInjectInitializer(injector)); - } - } - - @RequiredArgsConstructor - private static final class BungeeClientToProxyInjectInitializer - extends ChannelInboundHandlerAdapter { - - private final BungeeInjector injector; - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - injector.injectClient(ctx.channel(), true); - - ctx.pipeline().remove(this); - super.channelRead(ctx, msg); - } - } - - @RequiredArgsConstructor - private static final class BungeeProxyToServerInjectInitializer - extends ChannelOutboundHandlerAdapter { - - private final BungeeInjector injector; - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) - throws Exception { - injector.injectClient(ctx.channel(), false); - - ctx.pipeline().remove(this); - super.write(ctx, msg, promise); - } - } } From b469c0c0579bc91ce2ea37e73299b681d07ebb4e Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 16 Jul 2025 21:47:25 +0200 Subject: [PATCH 113/113] Remove LoginEvent usage in Floodgate-Spigot (#596) --- build-logic/src/main/kotlin/Versions.kt | 4 ++-- spigot/build.gradle.kts | 4 +--- .../org/geysermc/floodgate/listener/SpigotListener.java | 7 ++----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index f22b3d80..5c14da23 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -33,8 +33,8 @@ object Versions { const val guiceVersion = "6.0.0" const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" - const val cloudVersion = "2.0.0-SNAPSHOT" // for cloud-minecraft - const val cloudCore = "2.0.0-rc.1" + const val cloudVersion = "2.0.0-beta.11" // for cloud-minecraft + const val cloudCore = "2.0.0-rc.2" const val bstatsVersion = "3.0.2" const val javaWebsocketVersion = "1.5.2" diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index af449d2f..6e95bae1 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -13,9 +13,7 @@ indra { dependencies { api(projects.core) - //implementation("org.incendo", "cloud-paper", Versions.cloudVersion) - // TODO change back after https://github.com/incendo/cloud-minecraft is merged - implementation("com.github.onebeastchris.cloud-minecraft", "cloud-paper", "jitpack-SNAPSHOT") + implementation("org.incendo", "cloud-paper", Versions.cloudVersion) // hack to make pre 1.12 work implementation("com.google.guava", "guava", guavaVersion) diff --git a/spigot/src/main/java/org/geysermc/floodgate/listener/SpigotListener.java b/spigot/src/main/java/org/geysermc/floodgate/listener/SpigotListener.java index 3574af44..8c19dd74 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/listener/SpigotListener.java +++ b/spigot/src/main/java/org/geysermc/floodgate/listener/SpigotListener.java @@ -30,7 +30,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; @@ -43,11 +43,8 @@ public final class SpigotListener implements Listener { @Inject private FloodgateLogger logger; @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerLogin(PlayerLoginEvent event) { + public void onPlayerJoin(PlayerJoinEvent event) { UUID uniqueId = event.getPlayer().getUniqueId(); - if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { - return; - } // if there was another player with the same uuid online, // he would've been disconnected by now