mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-19 14:59:27 +00:00
Switch config system to Configurate (#5010)
* Start implementing Configurate config system * More development * Start migrating to Gson only * Progress * Update usage of WebUtils * Most things now use Gson for JSON * Allow tests to succeed by using new Gson version * Use slightly cleaner version for Version deserializer * Work around older Gson versions without record support * GeyserCustomSkullConfiguration uses Configurate * Fix regression in properties get * New config used in core * The configuration is gone. Long live the config. * More changes and migrations away from Jackson * Improve node ordering when updating configs * typo * Better check for ignoring non-configurate configs for considering comment moving * Ensure metrics UUID is valid * Initial advanced config * Remove Jackson; finish config value placements * Remove duplicate relocate declarations * Let annotations work * Renaming to PluginSpecific * Use global bStats config where possible * Fix test * Re-introduce asterisk behavior in configs * Remove GeyserPluginBootstrap as it's no longer necessary * Remove old config.yml file * Update Xbox achievement comment * Apply suggestions from code review Co-authored-by: chris <github@onechris.mozmail.com> * No need to remove values anymore * Fix: disable bstats relocation on platforms where it is not needed * ensure it builds * Update custom unavailable slot comment Co-authored-by: chris <github@onechris.mozmail.com> * Update cooldown image * Logger message for direct-compression still being enabled * oops * More explicit RuntimeException message Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> * Constant for 'system' locale * Better config JSON encoding (something is broken with Cloudflare; we'll figure it out * Fix broadcast port default * Add this file too * Update configurate branch * fix build * Fix: Allow using custom config file on Standalone, add relocation comment * Move config loading to GeyserBootstrap interface * Add and rename some config options, add section notes (#5390) * Add and rename some config options, add section notes * adjust message * Update core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java Co-authored-by: Eclipse <eclipse@eclipseisoffline.xyz> * Update core/src/main/java/org/geysermc/geyser/configuration/GeyserConfig.java Co-authored-by: Eclipse <eclipse@eclipseisoffline.xyz> * Update ConfigLoader.java * Update AdvancedConfig.java * clarify that we're talking about the HAProxy protocol * rename config option to use-haproxy-protocol * remove ominous warning sign on xbox auth warning * adjust wording --------- Co-authored-by: Eclipse <eclipse@eclipseisoffline.xyz> * Back to one config file * Some minor touchups * Configurate: Sectionification (#5904) * Init: config sections * Start on adding tests, move migrations over to ConfigMigrations class * Get rid of auth section again, rename that one config option, fix mtu migration * Move custom skulls config options to the bottom of the gameplay settings * Add more tests * Rename and migrate proxy-protocol-whitelisted-ips to haproxy-protocol-whitelisted-ips * Add automatic downloading of the GeyserOptionalPack * Revert "Add automatic downloading of the GeyserOptionalPack" This reverts commit65b96208fb. * Add more invalid config tests * Warn about emote-offhand-workaround removal * Add automatic loading of the GeyserOptionalPack (feature/configurate) (#5964) * Add automatic downloading of the GeyserOptionalPack * Warn about including the OptionalPack from extensions when Geyser is already including it instead of throwing. * Copy optional pack instead of downloading --------- Co-authored-by: onebeastchris <github@onechris.mozmail.com> * Remove unused variable * Start warning users not running Java 21 * Update tests, temporarily remove NumericRanges test * Remove duplicate advanced section from Geyser dump * Address some "reviews" * yeet md5 hash from geyser dump * Add info about number of resource packs / amount of mappings into Geyser dump * Re-enable invalid config loading test * Fix: allow-custom-skulls migration * Fix test * Add "enable-emotes" configuration option * Rename "emotes-enabled" to "show-emotes" * Only enable integrated pack when optional pack isn't present * Update integrated pack * Exclude jackson annotations, remove leftover debug print * Remove one-time config migration warnings as we don't have access to the logger at that stage * Throw more detailed descriptive error when loading resource packs from the "packs" folder, add another legacy config test * Fix NeoForge's fun module conflict * Re-add warning about moved functionality, fix Geyser-ViaProxy This reverts commitfbadfa574a. * oops * Move GeyserLegacyPingPassthrough to separate thread to avoid Standalone command locking issues --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> Co-authored-by: chris <github@onechris.mozmail.com> Co-authored-by: Eclipse <eclipse@eclipseisoffline.xyz> Co-authored-by: Aurora <auroranova8756@gmail.com>
This commit is contained in:
@@ -15,11 +15,12 @@ dependencies {
|
||||
}
|
||||
|
||||
platformRelocate("net.md_5.bungee.jni")
|
||||
platformRelocate("com.fasterxml.jackson")
|
||||
platformRelocate("net.kyori")
|
||||
platformRelocate("org.incendo")
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud and Configurate, should also be relocated
|
||||
platformRelocate("org.yaml") // Broken as of 1.20
|
||||
platformRelocate("org.spongepowered")
|
||||
platformRelocate("org.bstats")
|
||||
|
||||
// These dependencies are already present on the platform
|
||||
provided(libs.bungeecord.proxy)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 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/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.bungeecord;
|
||||
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import net.md_5.bungee.config.ConfigurationProvider;
|
||||
import net.md_5.bungee.config.YamlConfiguration;
|
||||
import org.geysermc.geyser.util.metrics.MetricsPlatform;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class BungeeMetrics implements MetricsPlatform {
|
||||
private final Configuration configuration;
|
||||
|
||||
public BungeeMetrics(Plugin plugin) throws IOException {
|
||||
// https://github.com/Bastian/bstats-metrics/blob/master/bungeecord/src/main/java/org/bstats/bungeecord/Metrics.java
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
bStatsFolder.mkdirs();
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
writeFile(configFile,
|
||||
"# bStats (https://bStats.org) collects some basic information for plugin authors, like how",
|
||||
"# many people use their plugin and their total player count. It's recommended to keep bStats",
|
||||
"# enabled, but if you're not comfortable with this, you can turn this setting off. There is no",
|
||||
"# performance penalty associated with having metrics enabled, and data sent to bStats is fully",
|
||||
"# anonymous.",
|
||||
"enabled: true",
|
||||
"serverUuid: \"" + UUID.randomUUID() + "\"",
|
||||
"logFailedRequests: false",
|
||||
"logSentData: false",
|
||||
"logResponseStatusText: false");
|
||||
}
|
||||
|
||||
this.configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enabled() {
|
||||
return configuration.getBoolean("enabled", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverUuid() {
|
||||
return configuration.getString("serverUuid");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logFailedRequests() {
|
||||
return configuration.getBoolean("logFailedRequests", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logSentData() {
|
||||
return configuration.getBoolean("logSentData", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logResponseStatusText() {
|
||||
return configuration.getBoolean("logResponseStatusText", false);
|
||||
}
|
||||
|
||||
private void writeFile(File file, String... lines) throws IOException {
|
||||
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
|
||||
for (String line : lines) {
|
||||
bufferedWriter.write(line);
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +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/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.bungeecord;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration {
|
||||
@JsonIgnore
|
||||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(GeyserBungeePlugin plugin) {
|
||||
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate");
|
||||
Path geyserDataFolder = plugin.getDataFolder().toPath();
|
||||
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener {
|
||||
listenerInfo.isPingPassthrough(),
|
||||
listenerInfo.getQueryPort(),
|
||||
listenerInfo.isQueryEnabled(),
|
||||
bootstrap.getGeyserConfig().getRemote().isUseProxyProtocol() // If Geyser is expecting HAProxy, so should the Bungee end
|
||||
bootstrap.config().advanced().java().useHaproxyProtocol() // If Geyser is expecting HAProxy, so should the Bungee end
|
||||
);
|
||||
|
||||
// The field that stores all listeners in BungeeCord
|
||||
@@ -191,7 +191,7 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener {
|
||||
}
|
||||
initChannel.invoke(channelInitializer, ch);
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression()) {
|
||||
if (bootstrap.config().advanced().java().disableCompression()) {
|
||||
ch.pipeline().addAfter(PipelineUtils.PACKET_ENCODER, "geyser-compression-disabler",
|
||||
new GeyserBungeeCompressionDisabler());
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
|
||||
try {
|
||||
event = future.get(100, TimeUnit.MILLISECONDS);
|
||||
} catch (Throwable cause) {
|
||||
String address = GeyserImpl.getInstance().getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : "<IP address withheld>";
|
||||
String address = GeyserImpl.getInstance().config().logPlayerIpAddresses() ? inetSocketAddress.toString() : "<IP address withheld>";
|
||||
GeyserImpl.getInstance().getLogger().error("Failed to get ping information for " + address, cause);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -33,25 +33,25 @@ import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserPluginConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.metrics.MetricsPlatform;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.bungee.BungeeCommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -61,13 +61,12 @@ import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
|
||||
private CommandRegistry commandRegistry;
|
||||
private GeyserBungeeConfiguration geyserConfig;
|
||||
private GeyserPluginConfig geyserConfig;
|
||||
private GeyserBungeeInjector geyserInjector;
|
||||
private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger());
|
||||
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
||||
@@ -102,12 +101,11 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
System.setProperty("Mcpl.io_uring", "true");
|
||||
}
|
||||
|
||||
if (!this.loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
|
||||
this.geyser = GeyserImpl.load(this);
|
||||
this.geyserInjector = new GeyserBungeeInjector(this);
|
||||
|
||||
// Registration of listeners occurs only once
|
||||
@@ -168,16 +166,15 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
|
||||
public void onGeyserEnable() {
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
}
|
||||
|
||||
// Force-disable query if enabled, or else Geyser won't enable
|
||||
for (ListenerInfo info : getProxy().getConfig().getListeners()) {
|
||||
if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) {
|
||||
if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.bedrock().port()) {
|
||||
try {
|
||||
Field queryField = ListenerInfo.class.getDeclaredField("queryEnabled");
|
||||
queryField.setAccessible(true);
|
||||
@@ -195,7 +192,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
if (!geyserConfig.motd().integratedPingPassthrough()) {
|
||||
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
} else {
|
||||
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
|
||||
@@ -232,8 +229,13 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserBungeeConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.BUNGEECORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserPluginConfig config() {
|
||||
return this.geyserConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -290,11 +292,29 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
if (getProxy().getPluginManager().getPlugin("floodgate") != null) {
|
||||
geyserConfig.loadFloodgate(this);
|
||||
return true;
|
||||
return getProxy().getPluginManager().getPlugin("floodgate") != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
Plugin floodgate = getProxy().getPluginManager().getPlugin("floodgate");
|
||||
Path geyserDataFolder = getDataFolder().toPath();
|
||||
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||
|
||||
return FloodgateKeyLoader.getKeyPath(geyserConfig, floodgateDataFolder, geyserDataFolder, geyserLogger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricsPlatform createMetricsPlatform() {
|
||||
try {
|
||||
return new BungeeMetrics(this);
|
||||
} catch (IOException e) {
|
||||
this.geyserLogger.debug("Integrated bStats support failed to load.");
|
||||
if (this.config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Optional<InetSocketAddress> findCompatibleListener() {
|
||||
@@ -303,20 +323,4 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
.map(info -> (InetSocketAddress) info.getSocketAddress())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
try {
|
||||
if (!getDataFolder().exists()) //noinspection ResultOfMethodCallIgnored
|
||||
getDataFolder().mkdir();
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"),
|
||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class GeyserBungeeUpdateListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(final PostLoginEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
final ProxiedPlayer player = event.getPlayer();
|
||||
if (player.hasPermission(Permissions.CHECK_UPDATE)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSource(player));
|
||||
|
||||
@@ -17,7 +17,7 @@ dependencies {
|
||||
shadowBundle(projects.core)
|
||||
includeTransitive(projects.core)
|
||||
|
||||
// These are NOT transitively included, and instead shadowed + relocated.
|
||||
// These are NOT transitively included, and instead shadowed (+ relocated, if not under the org.geyser namespace).
|
||||
// Avoids fabric complaining about non-SemVer versioning
|
||||
shadowBundle(libs.protocol.connection)
|
||||
shadowBundle(libs.protocol.common)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.fabricmc.api.EnvType;
|
||||
@@ -48,7 +49,7 @@ public class GeyserFabricDumpInfo extends BootstrapDumpInfo {
|
||||
private final String minecraftVersion;
|
||||
private final EnvType environmentType;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
@JsonAdapter(value = AsteriskSerializer.class)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final boolean onlineMode;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class GeyserFabricPlatform implements GeyserModPlatform {
|
||||
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
|
||||
if (floodgate.isPresent()) {
|
||||
Path floodgateDataFolder = FabricLoader.getInstance().getConfigDir().resolve("floodgate");
|
||||
bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
|
||||
bootstrap.loadFloodgate(floodgateDataFolder);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@ architectury {
|
||||
provided("org.cloudburstmc.math", "api")
|
||||
provided("com.google.errorprone", "error_prone_annotations")
|
||||
|
||||
// Jackson shipped by Minecraft is too old, so we shade & relocate our newer version
|
||||
relocate("com.fasterxml.jackson")
|
||||
|
||||
dependencies {
|
||||
// See https://github.com/google/guava/issues/6618
|
||||
modules {
|
||||
@@ -30,15 +27,12 @@ dependencies {
|
||||
shadowBundle(project(path = ":mod", configuration = "transformProductionNeoForge"))
|
||||
shadowBundle(projects.core)
|
||||
|
||||
// Minecraft (1.21.2+) includes jackson. But an old version!
|
||||
shadowBundle(libs.jackson.core)
|
||||
shadowBundle(libs.jackson.databind)
|
||||
shadowBundle(libs.jackson.dataformat.yaml)
|
||||
shadowBundle(libs.jackson.annotations)
|
||||
|
||||
// Let's shade in our own api
|
||||
shadowBundle(projects.api)
|
||||
|
||||
// this one is particularly dumb
|
||||
shadowBundle(libs.configurate.`interface`)
|
||||
|
||||
// cannot be shaded, since neoforge will complain if floodgate-neoforge tries to provide this
|
||||
include(projects.common)
|
||||
|
||||
@@ -61,11 +55,6 @@ tasks {
|
||||
remapModrinthJar {
|
||||
archiveBaseName.set("geyser-neoforge")
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
// Without this, jackson's service files are not relocated
|
||||
mergeServiceFiles()
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.geyser.platform.neoforge;
|
||||
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -47,7 +48,7 @@ public class GeyserNeoForgeDumpInfo extends BootstrapDumpInfo {
|
||||
private final String minecraftVersion;
|
||||
private final Dist dist;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
@JsonAdapter(value = AsteriskSerializer.class)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final boolean onlineMode;
|
||||
|
||||
@@ -72,7 +72,7 @@ public class GeyserNeoForgePlatform implements GeyserModPlatform {
|
||||
public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
|
||||
if (ModList.get().isLoaded("floodgate")) {
|
||||
Path floodgateDataFolder = FMLPaths.CONFIGDIR.get().resolve("floodgate");
|
||||
bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
|
||||
bootstrap.loadFloodgate(floodgateDataFolder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -31,11 +31,13 @@ import lombok.Setter;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserPluginConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.level.WorldManager;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
@@ -43,14 +45,10 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
||||
import org.geysermc.geyser.platform.mod.world.GeyserModWorldManager;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
@@ -69,7 +67,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
|
||||
@Setter
|
||||
private CommandRegistry commandRegistry;
|
||||
private GeyserModConfiguration geyserConfig;
|
||||
private GeyserPluginConfig geyserConfig;
|
||||
private GeyserModInjector geyserInjector;
|
||||
private final GeyserModLogger geyserLogger = new GeyserModLogger();
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
@@ -80,12 +78,11 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
instance = this;
|
||||
dataFolder = this.platform.dataFolder(this.platform.configPath());
|
||||
GeyserLocale.init(this);
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
this.geyser = GeyserImpl.load(this.platform.platformType(), this);
|
||||
this.geyser = GeyserImpl.load(this);
|
||||
}
|
||||
|
||||
public void onGeyserEnable() {
|
||||
@@ -95,16 +92,15 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
}
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
if (!geyserConfig.motd().integratedPingPassthrough()) {
|
||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
} else {
|
||||
this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
|
||||
@@ -145,7 +141,12 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserModConfiguration getGeyserConfig() {
|
||||
public @NonNull PlatformType platformType() {
|
||||
return this.platform.platformType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserPluginConfig config() {
|
||||
return geyserConfig;
|
||||
}
|
||||
|
||||
@@ -199,12 +200,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
if (isServer()) {
|
||||
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||
} else {
|
||||
// Set in the IntegratedServerMixin
|
||||
return geyserConfig.getRemote().port();
|
||||
}
|
||||
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||
}
|
||||
|
||||
public abstract boolean isServer();
|
||||
@@ -214,31 +210,23 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
return this.platform.testFloodgatePluginPresent(this);
|
||||
}
|
||||
|
||||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(Path floodgateDataFolder) {
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(geyserConfig, floodgateDataFolder, dataFolder, geyserLogger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return floodgateKeyPath;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public InputStream getResourceOrNull(String resource) {
|
||||
return this.platform.resolveResource(resource);
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
try {
|
||||
if (!dataFolder.toFile().exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
dataFolder.toFile().mkdir();
|
||||
}
|
||||
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
|
||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String getServerPlatform() {
|
||||
return server.getServerModName();
|
||||
|
||||
@@ -1,48 +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/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class GeyserModConfiguration extends GeyserJacksonConfiguration {
|
||||
@JsonIgnore
|
||||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(GeyserModBootstrap geyser, Path floodgateDataFolder) {
|
||||
Path geyserDataFolder = geyser.getConfigFolder();
|
||||
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return floodgateKeyPath;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class GeyserModInjector extends GeyserInjector {
|
||||
int index = ch.pipeline().names().indexOf("encoder");
|
||||
String baseName = index != -1 ? "encoder" : "outbound_config";
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression()) {
|
||||
if (bootstrap.config().advanced().java().disableCompression()) {
|
||||
ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserModCompressionDisabler());
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ public class GeyserModInjector extends GeyserInjector {
|
||||
childHandler = (ChannelInitializer<Channel>) childHandlerField.get(handler);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (bootstrap.getGeyserConfig().isDebugMode()) {
|
||||
if (bootstrap.config().debugMode()) {
|
||||
bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.geysermc.geyser.util.VersionCheckUtils;
|
||||
public final class GeyserModUpdateListener {
|
||||
public static void onPlayReady(ServerPlayer player) {
|
||||
// We could just not register the listener, but, this allows config reloading
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
// Should be creating this in the supplier, but we need it for the permission check.
|
||||
// Not a big deal currently because ModCommandSource doesn't load locale, so don't need to try to wait for it.
|
||||
ModCommandSource source = new ModCommandSource(player.createCommandSourceStack());
|
||||
|
||||
@@ -56,14 +56,13 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
|
||||
// If the LAN is opened, starts Geyser.
|
||||
GeyserModBootstrap instance = GeyserModBootstrap.getInstance();
|
||||
instance.setServer((MinecraftServer) (Object) this);
|
||||
instance.getGeyserConfig().getRemote().setPort(port);
|
||||
instance.onGeyserEnable();
|
||||
// Ensure player locale has been loaded, in case it's different from Java system language
|
||||
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
||||
// Give indication that Geyser is loaded
|
||||
Objects.requireNonNull(this.minecraft.player);
|
||||
this.minecraft.player.displayClientMessage(Component.literal(GeyserLocale.getPlayerLocaleString("geyser.core.start",
|
||||
this.minecraft.options.languageCode, "localhost", String.valueOf(GeyserImpl.getInstance().bedrockListener().port()))), false);
|
||||
this.minecraft.player.displayClientMessage(Component.literal(GeyserLocale.getPlayerLocaleString("geyser.core.start.ip_suppressed",
|
||||
this.minecraft.options.languageCode, String.valueOf(GeyserImpl.getInstance().bedrockListener().port()))), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,17 +31,25 @@ dependencies {
|
||||
compileOnly(libs.folia.api)
|
||||
|
||||
compileOnlyApi(libs.viaversion)
|
||||
|
||||
// For 1.16.5/1.17.1
|
||||
implementation(libs.gson.record.factory) {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
platformRelocate("it.unimi.dsi.fastutil")
|
||||
platformRelocate("com.fasterxml.jackson")
|
||||
// Relocate net.kyori but exclude the component logger
|
||||
platformRelocate("net.kyori", "net.kyori.adventure.text.logger.slf4j.ComponentLogger")
|
||||
platformRelocate("org.objectweb.asm")
|
||||
platformRelocate("me.lucko.commodore")
|
||||
platformRelocate("org.incendo")
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud and Configurate, should also be relocated
|
||||
platformRelocate("org.yaml") // Broken as of 1.20
|
||||
platformRelocate("org.spongepowered")
|
||||
platformRelocate("marcono1234.gson")
|
||||
platformRelocate("org.bstats")
|
||||
|
||||
provided(libs.viaversion)
|
||||
|
||||
tasks.withType<Jar> {
|
||||
|
||||
@@ -1,51 +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/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration {
|
||||
@JsonIgnore
|
||||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(GeyserSpigotPlugin plugin) {
|
||||
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate");
|
||||
Path geyserDataFolder = plugin.getDataFolder().toPath();
|
||||
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
@@ -42,7 +43,7 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo {
|
||||
private final String platformAPIVersion;
|
||||
private final boolean onlineMode;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
@JsonAdapter(value = AsteriskSerializer.class)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final List<PluginInfo> plugins;
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.DefaultEventLoopGroup;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -38,6 +40,8 @@ import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.network.netty.GeyserInjector;
|
||||
import org.geysermc.geyser.network.netty.LocalServerChannelWrapper;
|
||||
import org.geysermc.geyser.network.netty.LocalSession;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -123,7 +127,7 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
||||
int index = ch.pipeline().names().indexOf("encoder");
|
||||
String baseName = index != -1 ? "encoder" : "outbound_config";
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
|
||||
if (bootstrap.config().advanced().java().disableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
|
||||
ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
|
||||
}
|
||||
}
|
||||
@@ -158,7 +162,7 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
||||
}
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (bootstrap.getGeyserConfig().isDebugMode()) {
|
||||
if (bootstrap.config().debugMode()) {
|
||||
bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -178,8 +182,8 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
||||
private void workAroundWeirdBug(GeyserBootstrap bootstrap) {
|
||||
MinecraftProtocol protocol = new MinecraftProtocol();
|
||||
LocalSession session = new LocalSession(this.serverSocketAddress, InetAddress.getLoopbackAddress().getHostAddress(), protocol, Runnable::run);
|
||||
session.setFlag(MinecraftConstants.CLIENT_HOST, bootstrap.getGeyserConfig().getRemote().address());
|
||||
session.setFlag(MinecraftConstants.CLIENT_PORT, bootstrap.getGeyserConfig().getRemote().port());
|
||||
session.setFlag(MinecraftConstants.CLIENT_HOST, bootstrap.config().java().address());
|
||||
session.setFlag(MinecraftConstants.CLIENT_PORT, bootstrap.config().java().port());
|
||||
session.connect();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,11 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerLoadEvent;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.adapters.paper.PaperAdapters;
|
||||
@@ -50,7 +52,7 @@ import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserPluginConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.level.WorldManager;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
@@ -64,23 +66,20 @@ import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotLegacyNativ
|
||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorldManager;
|
||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.metrics.MetricsPlatform;
|
||||
import org.incendo.cloud.bukkit.BukkitCommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
|
||||
private CommandRegistry commandRegistry;
|
||||
private GeyserSpigotConfiguration geyserConfig;
|
||||
private GeyserPluginConfig geyserConfig;
|
||||
private GeyserSpigotInjector geyserInjector;
|
||||
private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ?
|
||||
new GeyserPaperLogger(this, getLogger()) : new GeyserSpigotLogger(getLogger());
|
||||
@@ -161,16 +160,16 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
// no-op
|
||||
}
|
||||
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
// We'll disable ourselves later
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
// Turn "(MC: 1.16.4)" into 1.16.4.
|
||||
this.minecraftVersion = Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0];
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this);
|
||||
this.geyser = GeyserImpl.load(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,16 +225,16 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
// Configs are loaded once early - so we can create the logger, then load extensions and finally register
|
||||
// extension commands in #onEnable. To ensure reloading geyser also reloads the geyser config, this exists
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(this.geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
}
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
if (!geyserConfig.motd().integratedPingPassthrough()) {
|
||||
this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
} else {
|
||||
if (ReflectedNames.checkPaperPingEvent()) {
|
||||
@@ -289,7 +288,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
}
|
||||
geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName());
|
||||
} catch (Throwable e) {
|
||||
if (geyserConfig.isDebugMode()) {
|
||||
if (geyserConfig.debugMode()) {
|
||||
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -363,8 +362,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserSpigotConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.SPIGOT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserPluginConfig config() {
|
||||
return this.geyserConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -455,32 +459,21 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
if (Bukkit.getPluginManager().getPlugin("floodgate") != null) {
|
||||
geyserConfig.loadFloodgate(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return Bukkit.getPluginManager().getPlugin("floodgate") != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
|
||||
try {
|
||||
if (!getDataFolder().exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
getDataFolder().mkdir();
|
||||
}
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml",
|
||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate");
|
||||
Path geyserDataFolder = getDataFolder().toPath();
|
||||
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||
|
||||
return true;
|
||||
return FloodgateKeyLoader.getKeyPath(geyserConfig, floodgateDataFolder, geyserDataFolder, geyserLogger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricsPlatform createMetricsPlatform() {
|
||||
return new SpigotMetrics(this);
|
||||
}
|
||||
|
||||
private void warnInvalidProxySetups(String platform) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class GeyserSpigotUpdateListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasPermission(Permissions.CHECK_UPDATE)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSource(player));
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 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/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.geysermc.geyser.util.metrics.MetricsPlatform;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class SpigotMetrics implements MetricsPlatform {
|
||||
private final YamlConfiguration config;
|
||||
|
||||
public SpigotMetrics(Plugin plugin) {
|
||||
// https://github.com/Bastian/bstats-metrics/blob/master/bukkit/src/main/java/org/bstats/bukkit/Metrics.java
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
if (!config.isSet("serverUuid")) {
|
||||
config.addDefault("enabled", true);
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
config.addDefault("logFailedRequests", false);
|
||||
config.addDefault("logSentData", false);
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
|
||||
// Inform the server owners about bStats
|
||||
config.options().header(
|
||||
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" +
|
||||
"many people use their plugin and their total player count. It's recommended to keep bStats\n" +
|
||||
"enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" +
|
||||
"performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" +
|
||||
"anonymous."
|
||||
).copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enabled() {
|
||||
return config.getBoolean("enabled", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverUuid() {
|
||||
return config.getString("serverUuid");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logFailedRequests() {
|
||||
return config.getBoolean("logFailedRequests", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logSentData() {
|
||||
return config.getBoolean("logSentData", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logResponseStatusText() {
|
||||
return config.getBoolean("logResponseStatusText", false);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ dependencies {
|
||||
|
||||
implementation(libs.bundles.jline)
|
||||
implementation(libs.bundles.log4j)
|
||||
|
||||
implementation(libs.gson.runtime)
|
||||
}
|
||||
|
||||
application {
|
||||
|
||||
@@ -25,11 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.platform.standalone;
|
||||
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import lombok.Getter;
|
||||
import org.apache.logging.log4j.Level;
|
||||
@@ -41,35 +36,32 @@ import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.standalone.StandaloneCloudCommandManager;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
import org.geysermc.geyser.configuration.ConfigLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.configuration.GeyserRemoteConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.LoopbackUtil;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
private StandaloneCloudCommandManager cloud;
|
||||
private CommandRegistry commandRegistry;
|
||||
private GeyserStandaloneConfiguration geyserConfig;
|
||||
private GeyserConfig geyserConfig;
|
||||
private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger();
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
private GeyserStandaloneGUI gui;
|
||||
@@ -80,9 +72,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
private GeyserImpl geyser;
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private static final Map<String, String> argsConfigKeys = new HashMap<>();
|
||||
private static final Map<NodePath, String> argsConfigKeys = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (System.getProperty("io.netty.leakDetection.level") == null) {
|
||||
@@ -99,8 +89,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
GeyserLocale.init(bootstrap);
|
||||
|
||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
|
||||
// Optionally, you can force the use of a GUI or no GUI by specifying args
|
||||
@@ -132,34 +120,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
// Split the argument by an =
|
||||
String[] argParts = arg.substring(2).split("=");
|
||||
if (argParts.length == 2) {
|
||||
// Split the config key by . to allow for nested options
|
||||
String[] configKeyParts = argParts[0].split("\\.");
|
||||
|
||||
// Loop the possible config options to check the passed key is valid
|
||||
boolean found = false;
|
||||
for (BeanPropertyDefinition property : availableProperties) {
|
||||
if (configKeyParts[0].equals(property.getName())) {
|
||||
if (configKeyParts.length > 1) {
|
||||
// Loop sub-section options to check the passed key is valid
|
||||
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the found key to the stored list for later usage
|
||||
if (found) {
|
||||
argsConfigKeys.put(argParts[0], argParts[1]);
|
||||
break;
|
||||
}
|
||||
argsConfigKeys.put(NodePath.of(argParts[0].split("\\.")), argParts[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.err.println(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg));
|
||||
@@ -189,19 +151,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
@Override
|
||||
public void onGeyserEnable() {
|
||||
try {
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml",
|
||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
||||
|
||||
handleArgsConfigOptions();
|
||||
|
||||
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
||||
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
|
||||
geyserConfig.getRemote().setAddress("127.0.0.1");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
this.geyserConfig = loadConfig(GeyserRemoteConfig.class);
|
||||
if (this.geyserConfig == null) {
|
||||
if (gui == null) {
|
||||
System.exit(1);
|
||||
} else {
|
||||
@@ -209,13 +160,11 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
return;
|
||||
}
|
||||
}
|
||||
geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
// Allow libraries like Protocol to have their debug information passthrough
|
||||
log4jLogger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO);
|
||||
log4jLogger.get().setLevel(geyserConfig.debugMode() ? Level.DEBUG : Level.INFO);
|
||||
|
||||
geyser = GeyserImpl.load(PlatformType.STANDALONE, this);
|
||||
geyser = GeyserImpl.load(this);
|
||||
|
||||
boolean reloading = geyser.isReloading();
|
||||
if (!reloading) {
|
||||
@@ -245,6 +194,14 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
geyserLogger.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends GeyserConfig> T loadConfig(Class<T> configClass) {
|
||||
return new ConfigLoader(this)
|
||||
.configFile(new File(getConfigFolder().toFile(), configFilename))
|
||||
.transformer(this::handleArgsConfigOptions)
|
||||
.load(configClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check using {@link java.awt.GraphicsEnvironment} that we are a headless client
|
||||
*
|
||||
@@ -273,8 +230,13 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.STANDALONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfig config() {
|
||||
return this.geyserConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,100 +292,47 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link BeanPropertyDefinition}s for the given class
|
||||
*
|
||||
* @param clazz The class to get the definitions for
|
||||
* @return A list of {@link BeanPropertyDefinition} for the given class
|
||||
*/
|
||||
public static List<BeanPropertyDefinition> getPOJOForClass(Class<?> clazz) {
|
||||
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz);
|
||||
|
||||
// Introspect the given type
|
||||
BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType);
|
||||
|
||||
// Find properties
|
||||
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
|
||||
|
||||
// Get the ignored properties
|
||||
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
|
||||
.findPropertyIgnoralByName(OBJECT_MAPPER.getSerializationConfig(), beanDescription.getClassInfo()).getIgnored();
|
||||
|
||||
// Filter properties removing the ignored ones
|
||||
return properties.stream()
|
||||
.filter(property -> !ignoredProperties.contains(property.getName()))
|
||||
.collect(Collectors.toList());
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return Path.of(geyserConfig.advanced().floodgateKeyFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a POJO property value on an object
|
||||
*
|
||||
* @param property The {@link BeanPropertyDefinition} to set
|
||||
* @param parentObject The object to alter
|
||||
* @param value The new value of the property
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) // Required for enum usage
|
||||
private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) {
|
||||
private static void setConfigOption(CommentedConfigurationNode node, Object value) throws SerializationException {
|
||||
Object parsedValue = value;
|
||||
|
||||
// Change the values type if needed
|
||||
if (int.class.equals(property.getRawPrimaryType())) {
|
||||
Class<?> clazz = node.raw().getClass();
|
||||
if (Integer.class == clazz) {
|
||||
parsedValue = Integer.valueOf((String) parsedValue);
|
||||
} else if (boolean.class.equals(property.getRawPrimaryType())) {
|
||||
} else if (Boolean.class == clazz) {
|
||||
parsedValue = Boolean.valueOf((String) parsedValue);
|
||||
} else if (Enum.class.isAssignableFrom(property.getRawPrimaryType())) {
|
||||
parsedValue = Enum.valueOf((Class<? extends Enum>) property.getRawPrimaryType(), ((String) parsedValue).toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
// Force the value to be set
|
||||
AnnotatedField field = property.getField();
|
||||
field.fixAccess(true);
|
||||
field.setValue(parentObject, parsedValue);
|
||||
node.set(parsedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments
|
||||
* Update the loaded config with any values passed in the command line arguments
|
||||
*/
|
||||
private void handleArgsConfigOptions() {
|
||||
// Get the available properties from the class
|
||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||
private void handleArgsConfigOptions(CommentedConfigurationNode node) {
|
||||
for (Map.Entry<NodePath, String> configKey : argsConfigKeys.entrySet()) {
|
||||
NodePath path = configKey.getKey();
|
||||
CommentedConfigurationNode subNode = node.node(path);
|
||||
if (subNode.virtual()) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.unrecognised", path));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> configKey : argsConfigKeys.entrySet()) {
|
||||
String[] configKeyParts = configKey.getKey().split("\\.");
|
||||
|
||||
// Loop over the properties looking for any matches against the stored one from the argument
|
||||
for (BeanPropertyDefinition property : availableProperties) {
|
||||
if (configKeyParts[0].equals(property.getName())) {
|
||||
if (configKeyParts.length > 1) {
|
||||
// Loop through the sub property if the first part matches
|
||||
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||
geyserLogger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
|
||||
// Set the sub property value on the config
|
||||
try {
|
||||
Object subConfig = property.getGetter().callOn(geyserConfig);
|
||||
setConfigOption(subProperty, subConfig, configKey.getValue());
|
||||
} catch (Exception e) {
|
||||
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
geyserLogger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
|
||||
// Set the property value on the config
|
||||
try {
|
||||
setConfigOption(property, geyserConfig, configKey.getValue());
|
||||
} catch (Exception e) {
|
||||
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
try {
|
||||
setConfigOption(subNode, configKey.getValue());
|
||||
geyserLogger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
} catch (SerializationException e) {
|
||||
geyserLogger.error("Failed to set config option: " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +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/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.standalone;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration {
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return Paths.get(getFloodgateKeyFile());
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
import org.apache.logging.log4j.io.IoBuilder;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
@@ -112,7 +113,12 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey
|
||||
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
log.debug(ChatColor.GRAY + message);
|
||||
log.debug(ChatColor.GRAY + "{}", message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(@Nullable Object object) {
|
||||
log.debug("{}", object);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,12 +16,13 @@ dependencies {
|
||||
api(libs.cloud.velocity)
|
||||
}
|
||||
|
||||
platformRelocate("com.fasterxml.jackson")
|
||||
platformRelocate("it.unimi.dsi.fastutil")
|
||||
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
|
||||
platformRelocate("org.yaml")
|
||||
platformRelocate("org.spongepowered")
|
||||
platformRelocate("org.bstats")
|
||||
platformRelocate("org.incendo")
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud and Configurate, should also be relocated
|
||||
|
||||
// These dependencies are already present on the platform
|
||||
provided(libs.velocity.api)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.geyser.platform.velocity;
|
||||
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import lombok.Getter;
|
||||
@@ -42,7 +43,7 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo {
|
||||
private final String platformVendor;
|
||||
private final boolean onlineMode;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
@JsonAdapter(value = AsteriskSerializer.class)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final List<PluginInfo> plugins;
|
||||
|
||||
@@ -128,7 +128,7 @@ public class GeyserVelocityInjector extends GeyserInjector {
|
||||
protected void initChannel(@NonNull Channel ch) throws Exception {
|
||||
initChannel.invoke(channelInitializer, ch);
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserVelocityCompressionDisabler.ENABLED) {
|
||||
if (bootstrap.config().advanced().java().disableCompression() && GeyserVelocityCompressionDisabler.ENABLED) {
|
||||
ch.pipeline().addAfter("minecraft-encoder", "geyser-compression-disabler",
|
||||
new GeyserVelocityCompressionDisabler());
|
||||
}
|
||||
|
||||
@@ -39,31 +39,31 @@ import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserPluginConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.velocity.command.VelocityCommandSource;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.metrics.MetricsPlatform;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.velocity.VelocityCommandManager;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.UUID;
|
||||
import java.util.Optional;
|
||||
|
||||
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
||||
public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
@@ -71,7 +71,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
private final ProxyServer proxyServer;
|
||||
private final PluginContainer container;
|
||||
private final GeyserVelocityLogger geyserLogger;
|
||||
private GeyserVelocityConfiguration geyserConfig;
|
||||
private GeyserPluginConfig geyserConfig;
|
||||
private GeyserVelocityInjector geyserInjector;
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
private CommandRegistry commandRegistry;
|
||||
@@ -106,13 +106,12 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
System.setProperty("Mcpl.io_uring", "true");
|
||||
}
|
||||
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
|
||||
this.geyser = GeyserImpl.load(this);
|
||||
this.geyserInjector = new GeyserVelocityInjector(proxyServer);
|
||||
|
||||
// We need to register commands here, rather than in onGeyserEnable which is invoked during the appropriate ListenerBoundEvent.
|
||||
@@ -139,16 +138,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
return;
|
||||
}
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
}
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
if (!geyserConfig.motd().integratedPingPassthrough()) {
|
||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
} else {
|
||||
this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer);
|
||||
@@ -178,7 +176,12 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserVelocityConfiguration getGeyserConfig() {
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.VELOCITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserPluginConfig config() {
|
||||
return geyserConfig;
|
||||
}
|
||||
|
||||
@@ -250,27 +253,26 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
var floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
|
||||
if (floodgate.isPresent()) {
|
||||
geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return floodgate.isPresent();
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
Optional<PluginContainer> floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
|
||||
Path floodgateDataPath = floodgate.isPresent() ? Paths.get("plugins/floodgate/") : null;
|
||||
return FloodgateKeyLoader.getKeyPath(geyserConfig, floodgateDataPath, configFolder, geyserLogger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricsPlatform createMetricsPlatform() {
|
||||
try {
|
||||
if (!configFolder.toFile().exists())
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
configFolder.toFile().mkdirs();
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(configFolder.resolve("config.yml").toFile(),
|
||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
return new VelocityMetrics(this.configFolder);
|
||||
} catch (IOException e) {
|
||||
this.geyserLogger.debug("Integrated bStats support failed to load.");
|
||||
if (this.config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class GeyserVelocityUpdateListener {
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerJoin(PostLoginEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasPermission(Permissions.CHECK_UPDATE)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSource(player));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
* Copyright (c) 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
|
||||
@@ -25,28 +25,45 @@
|
||||
|
||||
package org.geysermc.geyser.platform.velocity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
import org.bstats.config.MetricsConfig;
|
||||
import org.geysermc.geyser.util.metrics.MetricsPlatform;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class GeyserVelocityConfiguration extends GeyserJacksonConfiguration {
|
||||
@JsonIgnore
|
||||
private Path floodgateKeyPath;
|
||||
public final class VelocityMetrics implements MetricsPlatform {
|
||||
private final MetricsConfig config;
|
||||
|
||||
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
|
||||
Optional<PluginContainer> floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
|
||||
Path floodgateDataPath = floodgate.isPresent() ? Paths.get("plugins/floodgate/") : null;
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataPath, dataFolder.toPath(), plugin.getGeyserLogger());
|
||||
public VelocityMetrics(Path dataDirectory) throws IOException {
|
||||
// https://github.com/Bastian/bstats-metrics/blob/master/velocity/src/main/java/org/bstats/velocity/Metrics.java
|
||||
File configFile = dataDirectory.getParent().resolve("bStats").resolve("config.txt").toFile();
|
||||
this.config = new MetricsConfig(configFile, true);
|
||||
// No logger message is implemented as Velocity should print its own before we do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enabled() {
|
||||
return config.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverUuid() {
|
||||
return config.getServerUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logFailedRequests() {
|
||||
return config.isLogErrorsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logSentData() {
|
||||
return config.isLogSentDataEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logResponseStatusText() {
|
||||
return config.isLogResponseStatusTextEnabled();
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,9 @@ platformRelocate("net.kyori")
|
||||
platformRelocate("org.yaml")
|
||||
platformRelocate("it.unimi.dsi.fastutil")
|
||||
platformRelocate("org.cloudburstmc.netty")
|
||||
platformRelocate("org.bstats")
|
||||
platformRelocate("org.incendo")
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud and Configurate, should also be relocated
|
||||
|
||||
// These dependencies are already present on the platform
|
||||
provided(libs.viaproxy)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
package org.geysermc.geyser.platform.viaproxy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.protocoltranslator.viaproxy.ViaProxyConfig;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final
|
||||
public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
|
||||
|
||||
private RemoteConfiguration remote = new RemoteConfiguration() {
|
||||
@Override
|
||||
public boolean isForwardHost() {
|
||||
return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPingPassthroughInterval() {
|
||||
int interval = super.getPingPassthroughInterval();
|
||||
if (interval < 15 && ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
|
||||
// <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made
|
||||
interval = 15;
|
||||
}
|
||||
return interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteConfiguration getRemote() {
|
||||
return this.remote;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package org.geysermc.geyser.platform.viaproxy;
|
||||
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import lombok.Getter;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||
@@ -41,7 +42,7 @@ public class GeyserViaProxyDumpInfo extends BootstrapDumpInfo {
|
||||
private final String platformVersion;
|
||||
private final boolean onlineMode;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
@JsonAdapter(value = AsteriskSerializer.class)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final List<PluginInfo> plugins;
|
||||
|
||||
@@ -26,6 +26,7 @@ package org.geysermc.geyser.platform.viaproxy;
|
||||
|
||||
import net.raphimc.viaproxy.cli.ConsoleFormatter;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
|
||||
@@ -75,6 +76,13 @@ public class GeyserViaProxyLogger implements GeyserLogger, GeyserCommandSource {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(@Nullable Object object) {
|
||||
if (this.debug) {
|
||||
this.logger.debug(ConsoleFormatter.convert(String.valueOf(object)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String message, Object... arguments) {
|
||||
if (this.debug) {
|
||||
|
||||
@@ -36,7 +36,9 @@ import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ProxyStartEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ProxyStopEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ShouldVerifyOnlineModeEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ViaProxyLoadedEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.types.ITyped;
|
||||
import net.raphimc.viaproxy.protocoltranslator.viaproxy.ViaProxyConfig;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
@@ -47,18 +49,19 @@ import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.standalone.StandaloneCloudCommandManager;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.ConfigLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.configuration.GeyserPluginConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.viaproxy.listener.GeyserServerTransferListener;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.LoopbackUtil;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Files;
|
||||
@@ -67,10 +70,10 @@ import java.util.UUID;
|
||||
|
||||
public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap, EventRegistrar {
|
||||
|
||||
public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser");
|
||||
private static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser");
|
||||
|
||||
private final GeyserViaProxyLogger logger = new GeyserViaProxyLogger(LogManager.getLogger("Geyser"));
|
||||
private GeyserViaProxyConfiguration config;
|
||||
private GeyserPluginConfig geyserConfig;
|
||||
private GeyserImpl geyser;
|
||||
private StandaloneCloudCommandManager cloud;
|
||||
private CommandRegistry commandRegistry;
|
||||
@@ -79,10 +82,6 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ROOT_FOLDER.mkdirs();
|
||||
|
||||
GeyserLocale.init(this);
|
||||
this.onGeyserInitialize();
|
||||
|
||||
ViaProxy.EVENT_MANAGER.register(this);
|
||||
}
|
||||
|
||||
@@ -91,6 +90,12 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
this.onGeyserShutdown();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onViaProxyLoaded(ViaProxyLoadedEvent event) {
|
||||
GeyserLocale.init(this);
|
||||
this.onGeyserInitialize();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onConsoleCommand(final ConsoleCommandEvent event) {
|
||||
final String command = event.getCommand().startsWith("/") ? event.getCommand().substring(1) : event.getCommand();
|
||||
@@ -119,6 +124,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
if (event.getType() != ITyped.Type.POST || event.isLegacyPassthrough()) {
|
||||
return;
|
||||
}
|
||||
// TODO remove
|
||||
if (System.getProperty("geyser.viaproxy.disableIpPassthrough") != null) { // Temporary until Configurate branch is merged
|
||||
return;
|
||||
}
|
||||
@@ -147,11 +153,12 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
|
||||
@Override
|
||||
public void onGeyserInitialize() {
|
||||
if (!this.loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this);
|
||||
this.geyser = GeyserImpl.load(this);
|
||||
this.geyser.eventBus().register(this, new GeyserServerTransferListener());
|
||||
LoopbackUtil.checkAndApplyLoopback(this.logger);
|
||||
}
|
||||
@@ -164,7 +171,8 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
}
|
||||
boolean reloading = geyser.isReloading();
|
||||
if (reloading) {
|
||||
if (!this.loadConfig()) {
|
||||
geyserConfig = loadConfig(GeyserPluginConfig.class);
|
||||
if (geyserConfig == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -185,7 +193,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
// Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added
|
||||
this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser);
|
||||
}
|
||||
if (this.config.getRemote().authType() == AuthType.FLOODGATE) {
|
||||
if (this.geyserConfig.java().authType() == AuthType.FLOODGATE) {
|
||||
ViaProxy.getConfig().setPassthroughBungeecordPlayerInfo(true);
|
||||
}
|
||||
}
|
||||
@@ -201,8 +209,13 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfiguration getGeyserConfig() {
|
||||
return this.config;
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.VIAPROXY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserPluginConfig config() {
|
||||
return this.geyserConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,19 +272,36 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
try {
|
||||
final File configFile = FileUtils.fileOrCopiedFromResource(new File(ROOT_FOLDER, "config.yml"), "config.yml", s -> s.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.config = FileUtils.loadConfig(configFile, GeyserViaProxyConfiguration.class);
|
||||
} catch (IOException e) {
|
||||
this.logger.severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), e);
|
||||
return false;
|
||||
}
|
||||
this.config.getRemote().setAuthType(Files.isRegularFile(this.config.getFloodgateKeyPath()) ? AuthType.FLOODGATE : AuthType.OFFLINE);
|
||||
this.logger.setDebug(this.config.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(this.config, this.logger);
|
||||
return true;
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return new File(ROOT_FOLDER, geyserConfig.advanced().floodgateKeyFile()).toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends GeyserConfig> T loadConfig(Class<T> configClass) {
|
||||
T config = new ConfigLoader(this)
|
||||
.transformer(node -> {
|
||||
try {
|
||||
if (!ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE)) {
|
||||
node.node("java", "forward-host").set(true);
|
||||
}
|
||||
|
||||
var pingPassthroughInterval = node.node("ping-passthrough-interval");
|
||||
int interval = pingPassthroughInterval.getInt();
|
||||
if (interval < 15 && ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
|
||||
// <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made
|
||||
pingPassthroughInterval.set(15);
|
||||
}
|
||||
} catch (SerializationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.configFile(new File(ROOT_FOLDER, "config.yml"))
|
||||
.load(configClass);
|
||||
if (config != null) {
|
||||
this.geyserConfig = (GeyserPluginConfig) config;
|
||||
config.java().authType(Files.isRegularFile(getFloodgateKeyPath()) ? AuthType.FLOODGATE : AuthType.OFFLINE);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user