From 7653a626afe8ad6320299ef5a39437ad271846fd Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 2 Oct 2022 16:43:14 -0400 Subject: [PATCH] Update Sponge to API 8 (#2611) --- .../bungeecord/GeyserBungeeDumpInfo.java | 6 +- .../command/GeyserBungeeCommandExecutor.java | 3 + .../platform/spigot/GeyserSpigotDumpInfo.java | 5 +- .../command/GeyserSpigotCommandExecutor.java | 3 + bootstrap/sponge/build.gradle.kts | 18 +- .../platform/sponge/GeyserSpongeDumpInfo.java | 35 ++-- .../platform/sponge/GeyserSpongeLogger.java | 2 +- .../sponge/GeyserSpongePingPassthrough.java | 47 +++-- .../platform/sponge/GeyserSpongePlugin.java | 175 +++++++++++------- .../command/GeyserSpongeCommandExecutor.java | 65 ++++--- .../command/GeyserSpongeCommandManager.java | 30 ++- .../sponge/command/SpongeCommandSource.java | 17 +- .../resources/META-INF/sponge_plugins.json | 30 +++ .../sponge/src/main/resources/pack.mcmeta | 6 + .../velocity/GeyserVelocityDumpInfo.java | 5 +- .../GeyserVelocityCommandExecutor.java | 3 + .../kotlin/geyser.base-conventions.gradle.kts | 2 +- core/src/main/resources/languages | 2 +- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 2 +- 20 files changed, 293 insertions(+), 165 deletions(-) create mode 100644 bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json create mode 100644 bootstrap/sponge/src/main/resources/pack.mcmeta diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java index 938e2fc3a..2278d99d9 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java @@ -52,10 +52,8 @@ public class GeyserBungeeDumpInfo extends BootstrapDumpInfo { this.plugins = new ArrayList<>(); for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) { - String hostname; - if (AsteriskSerializer.showSensitive || (listener.getHost().getHostString().equals("") || listener.getHost().getHostString().equals("0.0.0.0"))) { - hostname = listener.getHost().getHostString(); - } else { + String hostname = listener.getHost().getHostString(); + if (!AsteriskSerializer.showSensitive && !(hostname.equals("") || hostname.equals("0.0.0.0"))) { hostname = "***"; } this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort())); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java index 6575f047c..2d02c9950 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java @@ -69,6 +69,9 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor return; } command.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + } else { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale()); + commandSender.sendMessage(ChatColor.RED + message); } } else { this.commandExecutor.getCommand("help").execute(session, commandSender, new String[0]); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java index 8055a375f..92c2fe16b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java @@ -51,8 +51,9 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo { this.platformVersion = Bukkit.getVersion(); this.platformAPIVersion = Bukkit.getBukkitVersion(); this.onlineMode = Bukkit.getOnlineMode(); - if (AsteriskSerializer.showSensitive || (Bukkit.getIp().equals("") || Bukkit.getIp().equals("0.0.0.0"))) { - this.serverIP = Bukkit.getIp(); + String ip = Bukkit.getIp(); + if (AsteriskSerializer.showSensitive || (ip.equals("") || ip.equals("0.0.0.0"))) { + this.serverIP = ip; } else { this.serverIP = "***"; } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java index 52779db23..61d394214 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java @@ -66,6 +66,9 @@ public class GeyserSpigotCommandExecutor extends GeyserCommandExecutor implement } geyserCommand.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); return true; + } else { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale()); + commandSender.sendMessage(ChatColor.RED + message); } } else { getCommand("help").execute(session, commandSender, new String[0]); diff --git a/bootstrap/sponge/build.gradle.kts b/bootstrap/sponge/build.gradle.kts index 8765c4390..3d89e8649 100644 --- a/bootstrap/sponge/build.gradle.kts +++ b/bootstrap/sponge/build.gradle.kts @@ -7,13 +7,8 @@ platformRelocate("io.netty") platformRelocate("it.unimi.dsi.fastutil") platformRelocate("com.google.common") platformRelocate("com.google.guava") -platformRelocate("net.kyori") - -// Exclude these dependencies -exclude("com.google.code.gson:*") -exclude("org.yaml:*") -exclude("org.slf4j:*") -exclude("org.ow2.asm:*") +platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl") +platformRelocate("net.kyori.adventure.nbt") // These dependencies are already present on the platform provided(libs.sponge.api) @@ -30,5 +25,14 @@ tasks.withType { exclude(dependency("org.yaml:.*")) exclude(dependency("org.slf4j:.*")) exclude(dependency("org.ow2.asm:.*")) + + // Exclude all Kyori dependencies except the legacy NBT serializer and NBT + exclude(dependency("net.kyori:adventure-api:.*")) + exclude(dependency("net.kyori:examination-api:.*")) + exclude(dependency("net.kyori:examination-string:.*")) + exclude(dependency("net.kyori:adventure-text-serializer-gson:.*")) + exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*")) + exclude(dependency("net.kyori:adventure-text-serializer-plain:.*")) + exclude(dependency("net.kyori:adventure-key:.*")) } } \ No newline at end of file diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java index e65684af2..fc1bff3ef 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java @@ -27,12 +27,18 @@ package org.geysermc.geyser.platform.sponge; import lombok.Getter; import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.text.AsteriskSerializer; import org.spongepowered.api.Platform; import org.spongepowered.api.Sponge; -import org.spongepowered.api.plugin.PluginContainer; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.metadata.PluginMetadata; +import org.spongepowered.plugin.metadata.model.PluginContributor; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @Getter public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { @@ -44,18 +50,25 @@ public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { private final List plugins; GeyserSpongeDumpInfo() { - super(); - PluginContainer container = Sponge.getPlatform().getContainer(Platform.Component.IMPLEMENTATION); - this.platformName = container.getName(); - this.platformVersion = container.getVersion().get(); - this.onlineMode = Sponge.getServer().getOnlineMode(); - this.serverIP = Sponge.getServer().getBoundAddress().get().getHostString(); - this.serverPort = Sponge.getServer().getBoundAddress().get().getPort(); + PluginContainer container = Sponge.platform().container(Platform.Component.IMPLEMENTATION); + PluginMetadata platformMeta = container.metadata(); + this.platformName = platformMeta.name().orElse("unknown"); + this.platformVersion = platformMeta.version().getQualifier(); + this.onlineMode = Sponge.server().isOnlineModeEnabled(); + Optional socketAddress = Sponge.server().boundAddress(); + String hostString = socketAddress.map(InetSocketAddress::getHostString).orElse("unknown"); + if (AsteriskSerializer.showSensitive || (hostString.equals("") || hostString.equals("0.0.0.0") || hostString.equals("unknown"))) { + this.serverIP = hostString; + } else { + this.serverIP = "***"; + } + this.serverPort = socketAddress.map(InetSocketAddress::getPort).orElse(-1); this.plugins = new ArrayList<>(); - for (PluginContainer plugin : Sponge.getPluginManager().getPlugins()) { - String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown"); - this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion().get(), pluginClass, plugin.getAuthors())); + for (PluginContainer plugin : Sponge.pluginManager().plugins()) { + PluginMetadata meta = plugin.metadata(); + List contributors = meta.contributors().stream().map(PluginContributor::name).collect(Collectors.toList()); + this.plugins.add(new PluginInfo(true, meta.name().orElse("unknown"), meta.version().toString(), meta.entrypoint(), contributors)); } } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java index 4ab4e5346..2bed78ac9 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java @@ -29,7 +29,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.GeyserLogger; -import org.slf4j.Logger; +import org.apache.logging.log4j.Logger; @AllArgsConstructor public class GeyserSpongeLogger implements GeyserLogger { diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java index a661061e2..f69a3ffb4 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java @@ -28,11 +28,12 @@ package org.geysermc.geyser.platform.sponge; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.spongepowered.api.MinecraftVersion; import org.spongepowered.api.Sponge; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.EventContext; import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.cause.Cause; -import org.spongepowered.api.event.cause.EventContext; import org.spongepowered.api.event.server.ClientPingServerEvent; import org.spongepowered.api.network.status.StatusClient; import org.spongepowered.api.profile.GameProfile; @@ -43,7 +44,7 @@ import java.util.Optional; public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { - private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer()); + private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.server()); private static Method SpongeStatusResponse_create; @@ -59,50 +60,46 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer); } - Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer()); + Object response = SpongeStatusResponse_create.invoke(null, Sponge.server()); event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } - Sponge.getEventManager().post(event); + Sponge.eventManager().post(event); GeyserPingInfo geyserPingInfo = new GeyserPingInfo( - event.getResponse().getDescription().toPlain(), + MessageTranslator.convertMessage(event.response().description()), new GeyserPingInfo.Players( - event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(), - event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline() + event.response().players().orElseThrow(IllegalStateException::new).max(), + event.response().players().orElseThrow(IllegalStateException::new).online() ), new GeyserPingInfo.Version( - event.getResponse().getVersion().getName(), + event.response().version().name(), GameProtocol.getJavaProtocolVersion()) // thanks for also not exposing this sponge ); - event.getResponse().getPlayers().get().getProfiles().stream() - .map(GameProfile::getName) - .map(op -> op.orElseThrow(IllegalStateException::new)) - .forEach(geyserPingInfo.getPlayerList()::add); + event.response().players().ifPresent(players -> players.profiles().stream() + .map(GameProfile::name) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(geyserPingInfo.getPlayerList()::add) + ); + return geyserPingInfo; } - @SuppressWarnings("NullableProblems") - private static class GeyserStatusClient implements StatusClient { - - private final InetSocketAddress remote; - - public GeyserStatusClient(InetSocketAddress remote) { - this.remote = remote; - } + private record GeyserStatusClient(InetSocketAddress remote) implements StatusClient { @Override - public InetSocketAddress getAddress() { + public InetSocketAddress address() { return this.remote; } @Override - public MinecraftVersion getVersion() { - return Sponge.getPlatform().getMinecraftVersion(); + public MinecraftVersion version() { + return Sponge.platform().minecraftVersion(); } @Override - public Optional getVirtualHost() { + public Optional virtualHost() { return Optional.empty(); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index 42040f6ab..1f9541631 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.platform.sponge; import com.google.inject.Inject; +import org.apache.logging.log4j.Logger; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -36,18 +37,23 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor; import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager; -import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; -import org.slf4j.Logger; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor; +import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.game.state.GameStartedServerEvent; -import org.spongepowered.api.event.game.state.GameStoppedEvent; -import org.spongepowered.api.plugin.Plugin; +import org.spongepowered.api.event.lifecycle.ConstructPluginEvent; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.event.lifecycle.StartedEngineEvent; +import org.spongepowered.api.event.lifecycle.StoppingEngineEvent; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; @@ -55,54 +61,134 @@ import java.nio.file.Path; import java.util.Map; import java.util.UUID; -@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Sponge", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") +@Plugin(value = "geyser") public class GeyserSpongePlugin implements GeyserBootstrap { + /** + * True if the plugin should be in a disabled state. + * This exists because you can't unregister or disable plugins in Sponge + */ + private boolean enabled = true; + + @Inject + private PluginContainer pluginContainer; + @Inject private Logger logger; @Inject @ConfigDir(sharedRoot = false) - private File configDir; + private Path configPath; - private GeyserSpongeCommandManager geyserCommandManager; + // Available after construction lifecycle private GeyserSpongeConfiguration geyserConfig; private GeyserSpongeLogger geyserLogger; + private GeyserImpl geyser; + private GeyserSpongeCommandManager geyserCommandManager; // Commands are only registered after command registration lifecycle + + // Available after StartedEngine lifecycle private IGeyserPingPassthrough geyserSpongePingPassthrough; - private GeyserImpl geyser; - public void onLoad() { + /** + * Only to be used for reloading + */ + @Override + public void onEnable() { + enabled = true; + onConstruction(null); + // new commands cannot be registered, and geyser's command manager does not need be reloaded + onStartedEngine(null); + } + + @Override + public void onDisable() { + enabled = false; + if (geyser != null) { + geyser.shutdown(); + geyser = null; + } + } + + /** + * Construct the configuration, logger, and command manager. command manager will only be filled with commands once + * the connector is started, but it allows us to register events in sponge. + * + * @param event Not used. + */ + @Listener + public void onConstruction(@Nullable ConstructPluginEvent event) { GeyserLocale.init(this); - if (!configDir.exists()) + File configDir = configPath.toFile(); + if (!configDir.exists()) { configDir.mkdirs(); + } File configFile; try { configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()), this); + + this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class); } catch (IOException ex) { logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed")); ex.printStackTrace(); + onDisable(); return; } - try { - this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class); - } catch (IOException ex) { - logger.warn(GeyserLocale.getLocaleStringLog("geyser.config.failed")); - ex.printStackTrace(); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); + + this.geyser = GeyserImpl.load(PlatformType.SPONGE, this); + + this.geyserCommandManager = new GeyserSpongeCommandManager(geyser); + this.geyserCommandManager.init(); + } + + /** + * Construct the {@link GeyserSpongeCommandManager} and register the commands + * + * @param event required to register the commands + */ + @Listener + public void onRegisterCommands(@Nonnull RegisterCommandEvent event) { + if (enabled) { + event.register(this.pluginContainer, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser"); + + for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { + Map commands = entry.getValue(); + if (commands.isEmpty()) { + continue; + } + + event.register(this.pluginContainer, new GeyserSpongeCommandExecutor(this.geyser, commands), entry.getKey().description().id()); + } + } + } + + /** + * Configure the config properly if remote address is auto. Start connector and ping passthrough, and register subcommands of /geyser + * + * @param event not required + */ + @Listener + public void onStartedEngine(@Nullable StartedEngineEvent event) { + if (!enabled) { return; } - if (Sponge.getServer().getBoundAddress().isPresent()) { - InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get(); + if (Sponge.server().boundAddress().isPresent()) { + InetSocketAddress javaAddr = Sponge.server().boundAddress().get(); - // Don't change the ip if its listening on all interfaces // By default this should be 127.0.0.1 but may need to be changed in some circumstances if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); + // Don't change the ip if its listening on all interfaces + if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { + this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); + } geyserConfig.getRemote().setPort(javaAddr.getPort()); } } @@ -111,14 +197,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap { geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port()); } - this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - - this.geyser = GeyserImpl.load(PlatformType.SPONGE, this); - } - - @Override - public void onEnable() { GeyserImpl.start(); if (geyserConfig.isLegacyPingPassthrough()) { @@ -126,25 +204,11 @@ public class GeyserSpongePlugin implements GeyserBootstrap { } else { this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough(); } - - this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), geyser); - this.geyserCommandManager.init(); - - Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser"); - - for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { - Map commands = entry.getValue(); - if (commands.isEmpty()) { - continue; - } - - Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(this.geyser, commands), entry.getKey().description().id()); - } } - @Override - public void onDisable() { - geyser.shutdown(); + @Listener + public void onEngineStopping(StoppingEngineEvent event) { + onDisable(); } @Override @@ -159,7 +223,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { @Override public GeyserCommandManager getGeyserCommandManager() { - return this.geyserCommandManager; + return geyserCommandManager; } @Override @@ -169,22 +233,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { @Override public Path getConfigFolder() { - return configDir.toPath(); - } - - @Listener - public void onServerStarting() { - onLoad(); - } - - @Listener - public void onServerStart(GameStartedServerEvent event) { - onEnable(); - } - - @Listener - public void onServerStop(GameStoppedEvent event) { - onDisable(); + return configPath; } @Override @@ -194,6 +243,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap { @Override public String getMinecraftServerVersion() { - return Sponge.getPlatform().getMinecraftVersion().getName(); + return Sponge.platform().minecraftVersion().name(); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java index 3598ea8c2..a1a0d99ad 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java @@ -25,81 +25,88 @@ package org.geysermc.geyser.platform.sponge.command; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; -import org.spongepowered.api.command.CommandCallable; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.CommandCompletion; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.command.parameter.ArgumentReader; -import javax.annotation.Nullable; import java.util.*; +import java.util.stream.Collectors; -public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements CommandCallable { +public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements org.spongepowered.api.command.Command.Raw { public GeyserSpongeCommandExecutor(GeyserImpl geyser, Map commands) { super(geyser, commands); } @Override - public CommandResult process(CommandSource source, String arguments) { - GeyserCommandSource commandSender = new SpongeCommandSource(source); - GeyserSession session = getGeyserSession(commandSender); + public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) { + GeyserCommandSource commandSource = new SpongeCommandSource(cause); + GeyserSession session = getGeyserSession(commandSource); - String[] args = arguments.split(" "); - if (args.length > 0) { + String[] args = arguments.input().split(" "); + // This split operation results in an array of length 1, containing a zero length string, if the input string is empty + if (args.length > 0 && !args[0].isEmpty()) { GeyserCommand command = getCommand(args[0]); if (command != null) { - if (!source.hasPermission(command.permission())) { - // Not ideal to use log here but we dont get a session - source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); + if (!cause.hasPermission(command.permission())) { + cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")).color(NamedTextColor.RED)); return CommandResult.success(); } if (command.isBedrockOnly() && session == null) { - source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only"))); + cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")).color(NamedTextColor.RED)); return CommandResult.success(); } - getCommand(args[0]).execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + command.execute(session, commandSource, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + } else { + cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.not_found")).color(NamedTextColor.RED)); } } else { - getCommand("help").execute(session, commandSender, new String[0]); + getCommand("help").execute(session, commandSource, new String[0]); } return CommandResult.success(); } @Override - public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) { - if (arguments.split(" ").length == 1) { - return tabComplete(new SpongeCommandSource(source)); + public List complete(CommandCause cause, ArgumentReader.Mutable arguments) { + if (arguments.input().split(" ").length == 1) { + return tabComplete(new SpongeCommandSource(cause)).stream().map(CommandCompletion::of).collect(Collectors.toList()); } return Collections.emptyList(); } @Override - public boolean testPermission(CommandSource source) { + public boolean canExecute(CommandCause cause) { return true; } @Override - public Optional getShortDescription(CommandSource source) { - return Optional.of(Text.of("The main command for Geyser.")); + public Optional shortDescription(CommandCause cause) { + return Optional.of(Component.text("The main command for Geyser.")); } @Override - public Optional getHelp(CommandSource source) { - return Optional.of(Text.of("/geyser help")); + public Optional extendedDescription(CommandCause cause) { + return shortDescription(cause); } @Override - public Text getUsage(CommandSource source) { - return Text.of("/geyser help"); + public Optional help(@NotNull CommandCause cause) { + return Optional.of(Component.text("/geyser help")); + } + + @Override + public Component usage(CommandCause cause) { + return Component.text("/geyser help"); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java index 8e981f72a..d83e3a723 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java @@ -25,25 +25,37 @@ package org.geysermc.geyser.platform.sponge.command; +import net.kyori.adventure.text.Component; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandMapping; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.manager.CommandMapping; + +import java.util.Optional; public class GeyserSpongeCommandManager extends GeyserCommandManager { - private final org.spongepowered.api.command.CommandManager handle; - public GeyserSpongeCommandManager(org.spongepowered.api.command.CommandManager handle, GeyserImpl geyser) { + public GeyserSpongeCommandManager(GeyserImpl geyser) { super(geyser); - - this.handle = handle; } @Override public String description(String command) { - return handle.get(command).map(CommandMapping::getCallable) - .map(callable -> callable.getShortDescription(Sponge.getServer().getConsole()).orElse(Text.EMPTY)) - .orElse(Text.EMPTY).toPlain(); + if (!Sponge.isServerAvailable()) { + return ""; + } + + // Note: The command manager may be replaced at any point during the game lifecycle + return Sponge.server().commandManager().commandMapping(command) + .map(this::description) + .map(Optional::get) + .map(MessageTranslator::convertMessage) + .orElse(""); + } + + public Optional description(CommandMapping mapping) { + return mapping.registrar().shortDescription(CommandCause.create(), mapping); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java index 12fdcb989..31dccc1fb 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java @@ -26,29 +26,30 @@ package org.geysermc.geyser.platform.sponge.command; import lombok.AllArgsConstructor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.command.GeyserCommandSource; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.source.ConsoleSource; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; @AllArgsConstructor public class SpongeCommandSource implements GeyserCommandSource { - private CommandSource handle; + private final CommandCause handle; @Override public String name() { - return handle.getName(); + return handle.friendlyIdentifier().orElse(handle.identifier()); } @Override - public void sendMessage(String message) { - handle.sendMessage(Text.of(message)); + public void sendMessage(@NonNull String message) { + handle.audience().sendMessage(LegacyComponentSerializer.legacySection().deserialize(message)); } @Override public boolean isConsole() { - return handle instanceof ConsoleSource; + return !(handle.cause().root() instanceof ServerPlayer); } @Override diff --git a/bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json b/bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json new file mode 100644 index 000000000..2540f87b7 --- /dev/null +++ b/bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json @@ -0,0 +1,30 @@ +{ + "loader": { + "name": "java_plain", + "version": "1.0" + }, + "license": "MIT", + "plugins": [ + { + "id": "${id}", + "name": "${name}-Sponge", + "version": "${version}", + "entrypoint": "org.geysermc.geyser.platform.sponge.GeyserSpongePlugin", + "description": "${description}", + "links": { + "homepage": "${url}" + }, + "contributors": [ + { + "name": "${author}" + } + ], + "dependencies": [ + { + "id": "spongeapi", + "version": "8.0.0" + } + ] + } + ] +} diff --git a/bootstrap/sponge/src/main/resources/pack.mcmeta b/bootstrap/sponge/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..19e8dca71 --- /dev/null +++ b/bootstrap/sponge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "Geyser for Sponge", + "pack_format": 6 + } +} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java index 9f429cc83..b2765d3b2 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java @@ -51,8 +51,9 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo { this.platformVersion = proxy.getVersion().getVersion(); this.platformVendor = proxy.getVersion().getVendor(); this.onlineMode = proxy.getConfiguration().isOnlineMode(); - if (AsteriskSerializer.showSensitive || (proxy.getBoundAddress().getHostString().equals("") || proxy.getBoundAddress().getHostString().equals("0.0.0.0"))) { - this.serverIP = proxy.getBoundAddress().getHostString(); + String hostString = proxy.getBoundAddress().getHostString(); + if (AsteriskSerializer.showSensitive || (hostString.equals("") || hostString.equals("0.0.0.0"))) { + this.serverIP = hostString; } else { this.serverIP = "***"; } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java index c77a3daef..c89c35b06 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java @@ -63,6 +63,9 @@ public class GeyserVelocityCommandExecutor extends GeyserCommandExecutor impleme return; } command.execute(session, sender, invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]); + } else { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", sender.locale()); + sender.sendMessage(ChatColor.RED + message); } } else { getCommand("help").execute(session, sender, new String[0]); diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index ac652764b..9414655bc 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -9,7 +9,7 @@ dependencies { tasks { processResources { - filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) { + filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json")) { expand( "id" to "Geyser", "name" to "Geyser", diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 51d6f5ba7..a9cf5999a 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 51d6f5ba7d85bfda318879dad34481d9ef4d488d +Subproject commit a9cf5999af605902b18dd5c77d3562481f8d7f3d diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 2c68dab9d..f1c9c2fbb 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 2c68dab9d751f78b2f5b0298da5e338ad6bc07ca +Subproject commit f1c9c2fbba0e102dc4f8c96dd9485f7ec9768174 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5f9d72d57..28b687f9b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ adapters = "1.5-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.0.0" -sponge = "7.1.0" +sponge = "8.0.0" [libraries] jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" }