diff --git a/.checkstyle/suppressions.xml b/.checkstyle/suppressions.xml index d6398acd..530d6e64 100644 --- a/.checkstyle/suppressions.xml +++ b/.checkstyle/suppressions.xml @@ -2,7 +2,7 @@ - + diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 152c45f5..6a96942c 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -95,6 +95,7 @@ body: options: - Spigot / Bukkit - Folia + - Minestom - BungeeCord - Velocity - Other diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cac2568a..d3e7fcab 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -66,3 +66,4 @@ jobs: bungee/build/libs/apollo-bungee-${{ env.VERSION }}.jar velocity/build/libs/apollo-velocity-${{ env.VERSION }}.jar folia/build/libs/apollo-folia-${{ env.VERSION }}.jar + minestom/build/libs/apollo-minestom-${{ env.VERSION }}.jar diff --git a/README.md b/README.md index baefb25d..bbcce3e3 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ The output jars can be found in the `build/libs` directory relative to each plat - Bukkit: `bukkit/plugin/build/libs` - Folia: `folia/build/libs` +- Minestom: `minestom/build/libs` - BungeeCord: `bungee/build/libs` - Velocity: `velocity/build/libs` @@ -42,7 +43,7 @@ The Apollo project is split into several modules. - **API** - The publicly available interface for developers wishing to create custom integrations with Lunar Client. - **Common** - The abstraction used by platform modules to reduce duplicate code and implement the protocol for Lunar Client. -- **Bukkit, Folia, BungeeCord, Velocity** - Are modules that implement the common module for each respective platform. +- **Bukkit, Folia, Minestom, BungeeCord, Velocity** - Are modules that implement the common module for each respective platform. Contributions can be made to Apollo by creating a pull request for improvements or fixes. For new feature ideas please consider making a suggestion by creating an [issue](https://github.com/LunarClient/Apollo/issues) or joining our [discord](https://lunarclient.dev/discord). diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 4cc32fc7..26b1ad76 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -9,6 +9,7 @@ setupPlatformDependency("bukkit", "bukkitJar") setupPlatformDependency("bungee", "bungeeJar") setupPlatformDependency("velocity", "velocityJar", 17) setupPlatformDependency("folia", "foliaJar", 21) +setupPlatformDependency("minestom", "minestomJar", 21) val main by sourceSets @@ -29,6 +30,9 @@ dependencies { "folia"(main.output) "folia"(libs.folia) + + "minestom"(main.output) + "minestom"(libs.minestom) } publishShadowJar() diff --git a/api/src/main/java/com/lunarclient/apollo/ApolloPlatform.java b/api/src/main/java/com/lunarclient/apollo/ApolloPlatform.java index a7820b41..8ea25ec8 100644 --- a/api/src/main/java/com/lunarclient/apollo/ApolloPlatform.java +++ b/api/src/main/java/com/lunarclient/apollo/ApolloPlatform.java @@ -44,6 +44,14 @@ public interface ApolloPlatform { */ Kind getKind(); + /** + * Returns the platform type. + * + * @return the platform type + * @since 1.2.0 + */ + Platform getPlatform(); + /** * Returns the platform options that don't belong to a specific module. * @@ -93,4 +101,18 @@ enum Kind { SERVER, PROXY } + + /** + * Represents the platform type. + * + * @since 1.2.0 + */ + enum Platform { + BUKKIT, + FOLIA, + MINESTOM, + BUNGEE, + VELOCITY + } + } diff --git a/api/src/main/java/com/lunarclient/apollo/stats/ApolloStats.java b/api/src/main/java/com/lunarclient/apollo/stats/ApolloStats.java index eeb03f59..03b16d93 100644 --- a/api/src/main/java/com/lunarclient/apollo/stats/ApolloStats.java +++ b/api/src/main/java/com/lunarclient/apollo/stats/ApolloStats.java @@ -68,7 +68,7 @@ public interface ApolloStats { List getPlugins(); /** - * Gets the servers platform subtype (Bukkit, BungeeCord, Velocity...). + * Gets the servers platform subtype (Bukkit, Folia, Minestom, BungeeCord, Velocity...). * * @return the servers platform subtype * @since 1.0.0 diff --git a/api/src/minestom/java/com/lunarclient/apollo/MinestomApollo.java b/api/src/minestom/java/com/lunarclient/apollo/MinestomApollo.java new file mode 100644 index 00000000..fa8b42de --- /dev/null +++ b/api/src/minestom/java/com/lunarclient/apollo/MinestomApollo.java @@ -0,0 +1,102 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo; + +import com.lunarclient.apollo.common.ApolloEntity; +import com.lunarclient.apollo.player.ApolloPlayer; +import com.lunarclient.apollo.player.ApolloPlayerManager; +import com.lunarclient.apollo.recipients.Recipients; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import lombok.NonNull; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Player; + +/** + * Utility class for converting objects to and from their corresponding Minestom + * representations with additional helper methods for easier integration. + * + * @since 1.2.0 + */ +public final class MinestomApollo { + + /** + * Runs a specified operation for a {@link Player}. + * + * @param player the player + * @param playerConsumer the operation to be performed + * @since 1.2.0 + */ + public static void runForPlayer(@NonNull Player player, @NonNull Consumer playerConsumer) { + runForPlayer(player.getUuid(), playerConsumer); + } + + /** + * Runs a specified operation for a {@link ApolloPlayer} from the provided {@link UUID}. + * + * @param playerUuid the player + * @param playerConsumer the operation to be performed + * @since 1.2.0 + */ + public static void runForPlayer(@NonNull UUID playerUuid, @NonNull Consumer playerConsumer) { + Apollo.getPlayerManager().getPlayer(playerUuid).ifPresent(playerConsumer); + } + + /** + * Converts a {@link Collection} of {@link Player}s to an {@link Recipients}. + * + * @param players the players + * @return the recipients object containing the converted ApolloPlayer objects + * @since 1.2.0 + */ + public static Recipients getRecipientsFrom(@NonNull Collection players) { + ApolloPlayerManager playerManager = Apollo.getPlayerManager(); + List apolloPlayers = players.stream() + .map(player -> playerManager.getPlayer(player.getUuid())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + + return Recipients.of(apolloPlayers); + } + + /** + * Converts a {@link Entity} to an {@link ApolloEntity} object. + * + * @param entity the entity + * @return the converted apollo entity object + * @since 1.2.0 + */ + public static ApolloEntity toApolloEntity(@NonNull Entity entity) { + return new ApolloEntity(entity.getEntityId(), entity.getUuid()); + } + + private MinestomApollo() { + } + +} diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 5fb087bf..375c85d0 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -43,6 +43,11 @@ fun Project.setupPlatforms() { tasks.named("javadoc", Javadoc::class) { source(sourceSets.map { it.allJava }) classpath += sourceSets.map { it.compileClasspath }.reduce { first, second -> first + second } + + val javaToolchains = project.extensions.getByType(JavaToolchainService::class.java) + javadocTool.set(javaToolchains.javadocToolFor { + languageVersion.set(JavaLanguageVersion.of(21)) + }) } } } diff --git a/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java b/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java index 013a3abd..5e732585 100644 --- a/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java +++ b/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java @@ -23,8 +23,8 @@ */ package com.lunarclient.apollo; -import com.lunarclient.apollo.command.impl.ApolloCommand; -import com.lunarclient.apollo.command.impl.LunarClientCommand; +import com.lunarclient.apollo.command.BukkitApolloCommand; +import com.lunarclient.apollo.command.BukkitLunarClientCommand; import com.lunarclient.apollo.listener.ApolloMetadataListener; import com.lunarclient.apollo.listener.ApolloPlayerListener; import com.lunarclient.apollo.listener.ApolloWorldListener; @@ -174,8 +174,8 @@ public void onEnable() { (channel, player, bytes) -> ApolloManager.getNetworkManager().receivePacket(player.getUniqueId(), bytes) ); - this.plugin.getCommand("apollo").setExecutor(new ApolloCommand()); - this.plugin.getCommand("lunarclient").setExecutor(new LunarClientCommand()); + this.plugin.getCommand("apollo").setExecutor(new BukkitApolloCommand()); + this.plugin.getCommand("lunarclient").setExecutor(new BukkitLunarClientCommand()); ApolloManager.getStatsManager().enable(); ApolloManager.getVersionManager().checkForUpdates(); @@ -195,6 +195,11 @@ public Kind getKind() { return Kind.SERVER; } + @Override + public Platform getPlatform() { + return Platform.BUKKIT; + } + @Override public String getApolloVersion() { return this.plugin.getDescription().getVersion(); diff --git a/bukkit/src/main/java/com/lunarclient/apollo/command/BukkitApolloCommand.java b/bukkit/src/main/java/com/lunarclient/apollo/command/BukkitApolloCommand.java index 2ba91829..fadd27ea 100644 --- a/bukkit/src/main/java/com/lunarclient/apollo/command/BukkitApolloCommand.java +++ b/bukkit/src/main/java/com/lunarclient/apollo/command/BukkitApolloCommand.java @@ -23,51 +23,44 @@ */ package com.lunarclient.apollo.command; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import lombok.NonNull; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.ApolloPlatform; +import com.lunarclient.apollo.command.type.ApolloCommand; +import com.lunarclient.apollo.common.ApolloComponent; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; /** - * Provides common command functions for Bukkit. + * The general Apollo command. * - * @param the sender type - * @since 1.0.9 + * @since 1.0.5 */ -public abstract class BukkitApolloCommand extends AbstractApolloCommand { +public final class BukkitApolloCommand extends ApolloCommand implements CommandExecutor { /** - * Returns a new instance of a Bukkit command. + * Returns a new instance of this command. * - * @param textConsumer the consumer for sending messages to the sender - * @since 1.0.9 + * @since 1.0.5 */ - public BukkitApolloCommand(BiConsumer textConsumer) { - super(textConsumer); + public BukkitApolloCommand() { + super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); } - /** - * Handles a player argument; if the provided player doesn't exist, a not found message - * is sent to the sender. Otherwise, the player is passed to the provided player consumer. - * - * @param sender the command sender - * @param argument the argument passed from the command execution - * @param playerConsumer a consumer used for processing a desired action if the player is found - * @since 1.0.9 - */ - protected void handlePlayerArgument(@NonNull T sender, @NonNull String argument, @NonNull Consumer playerConsumer) { - Player player = Bukkit.getPlayer(argument); - - if (player == null) { - this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) - .append(Component.text(argument, NamedTextColor.RED)) - .append(Component.text("' not found!", NamedTextColor.RED))); - return; + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if(args.length < 1) { + this.getCurrentVersion(sender); + } else if(args[0].equalsIgnoreCase("reload")) { + this.reloadConfiguration(sender); + } else if(args[0].equalsIgnoreCase("update")) { + ApolloManager.getVersionManager().forceUpdate( + ApolloPlatform.Platform.BUKKIT, + message -> this.textConsumer.accept(sender, message) + ); } - playerConsumer.accept(player); + return true; } + } diff --git a/bukkit/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java b/bukkit/src/main/java/com/lunarclient/apollo/command/BukkitLunarClientCommand.java similarity index 56% rename from bukkit/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java rename to bukkit/src/main/java/com/lunarclient/apollo/command/BukkitLunarClientCommand.java index eabd32bc..b33e03dd 100644 --- a/bukkit/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java +++ b/bukkit/src/main/java/com/lunarclient/apollo/command/BukkitLunarClientCommand.java @@ -21,56 +21,65 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.lunarclient.apollo.command.impl; +package com.lunarclient.apollo.command; import com.lunarclient.apollo.Apollo; -import com.lunarclient.apollo.command.BukkitApolloCommand; +import com.lunarclient.apollo.command.type.LunarClientCommand; import com.lunarclient.apollo.common.ApolloComponent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; /** * The general Lunar Client command. * * @since 1.0.9 */ -public final class LunarClientCommand extends BukkitApolloCommand implements CommandExecutor { +public final class BukkitLunarClientCommand extends LunarClientCommand implements CommandExecutor { /** * Returns a new instance of this command. * * @since 1.0.9 */ - public LunarClientCommand() { + public BukkitLunarClientCommand() { super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); this.setUsage("/lunarclient "); } @Override - public boolean onCommand(CommandSender commandSender, Command command, String label, String[] args) { + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if(args.length != 1) { - this.sendCommandUsage(commandSender); + this.sendCommandUsage(sender); return true; } - this.handlePlayerArgument(commandSender, args[0], player -> { - Component message = Component.text("Player ", NamedTextColor.GRAY) - .append(Component.text(player.getName(), NamedTextColor.AQUA)) - .append(Component.text(" is ", NamedTextColor.GRAY)); + Player player = Bukkit.getPlayer(args[0]); - if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { - message = message.append(Component.text("using ", NamedTextColor.GREEN)); - } else { - message = message.append(Component.text("not using ", NamedTextColor.RED)); - } + if (player == null) { + this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) + .append(Component.text(args[0], NamedTextColor.RED)) + .append(Component.text("' not found!", NamedTextColor.RED))); + return true; + } + + Component message = Component.text("Player ", NamedTextColor.GRAY) + .append(Component.text(player.getName(), NamedTextColor.AQUA)) + .append(Component.text(" is ", NamedTextColor.GRAY)); + + if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { + message = message.append(Component.text("using ", NamedTextColor.GREEN)); + } else { + message = message.append(Component.text("not using ", NamedTextColor.RED)); + } - message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); - this.textConsumer.accept(commandSender, message); - }); + message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); + this.textConsumer.accept(sender, message); return true; } diff --git a/bukkit/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java b/bukkit/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java index ce6a018b..69997978 100644 --- a/bukkit/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java +++ b/bukkit/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java @@ -25,6 +25,7 @@ import com.lunarclient.apollo.Apollo; import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.api.response.VersionResponse; import com.lunarclient.apollo.event.ApolloListener; import com.lunarclient.apollo.event.ApolloReceivePacketEvent; import com.lunarclient.apollo.event.EventBus; @@ -87,13 +88,27 @@ private void onPlayerQuit(PlayerQuitEvent event) { @EventHandler private void onPlayerJoin(PlayerJoinEvent event) { - if (!ApolloVersionManager.NEEDS_UPDATE) { + VersionResponse updateAssets = ApolloManager.getVersionManager().getUpdateAssets(); + if (updateAssets == null) { + return; + } + + if (!Apollo.getPlatform().getOptions().get(ApolloVersionManager.SEND_UPDATE_MESSAGE)) { return; } Player player = event.getPlayer(); - if (player.isOp()) { - player.sendMessage(ChatColor.YELLOW + ApolloVersionManager.UPDATE_MESSAGE); + String version = updateAssets.getVersion(); + + if (version != null && player.isOp()) { + String message = ChatColor.YELLOW + "[Apollo] A new version of Apollo is available! Latest release: " + + ChatColor.GOLD + version + + ChatColor.YELLOW + " Please update by running " + + ChatColor.GOLD + "/apollo update " + + ChatColor.YELLOW + "or by downloading the latest build from " + + ChatColor.GOLD + "https://lunarclient.dev/apollo/downloads"; + + player.sendMessage(message); } } diff --git a/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java b/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java index dc2aa3e8..8ef6a4b3 100644 --- a/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java +++ b/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java @@ -23,8 +23,8 @@ */ package com.lunarclient.apollo; -import com.lunarclient.apollo.command.impl.ApolloCommand; -import com.lunarclient.apollo.command.impl.LunarClientCommand; +import com.lunarclient.apollo.command.BungeeApolloCommand; +import com.lunarclient.apollo.command.BungeeLunarClientCommand; import com.lunarclient.apollo.listener.ApolloMetadataListener; import com.lunarclient.apollo.listener.ApolloPlayerListener; import com.lunarclient.apollo.loader.PlatformPlugin; @@ -151,8 +151,8 @@ public void onEnable() { PluginManager pluginManager = server.getPluginManager(); pluginManager.registerListener(this.plugin, new ApolloMetadataListener(this.plugin)); pluginManager.registerListener(this.plugin, new ApolloPlayerListener()); - pluginManager.registerCommand(this.plugin, ApolloCommand.create()); - pluginManager.registerCommand(this.plugin, LunarClientCommand.create()); + pluginManager.registerCommand(this.plugin, BungeeApolloCommand.create()); + pluginManager.registerCommand(this.plugin, BungeeLunarClientCommand.create()); ApolloManager.getStatsManager().enable(); ApolloManager.getVersionManager().checkForUpdates(); @@ -168,6 +168,11 @@ public Kind getKind() { return Kind.PROXY; } + @Override + public Platform getPlatform() { + return Platform.BUNGEE; + } + @Override public String getApolloVersion() { return this.plugin.getDescription().getVersion(); diff --git a/bungee/src/main/java/com/lunarclient/apollo/command/BungeeApolloCommand.java b/bungee/src/main/java/com/lunarclient/apollo/command/BungeeApolloCommand.java index 8b01e4e5..7e0c9d17 100644 --- a/bungee/src/main/java/com/lunarclient/apollo/command/BungeeApolloCommand.java +++ b/bungee/src/main/java/com/lunarclient/apollo/command/BungeeApolloCommand.java @@ -23,51 +23,52 @@ */ package com.lunarclient.apollo.command; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import lombok.NonNull; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.connection.ProxiedPlayer; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.ApolloPlatform; +import com.lunarclient.apollo.command.type.ApolloCommand; +import com.lunarclient.apollo.common.ApolloComponent; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.plugin.Command; /** - * Provides common command functions for Bungee. + * The general Apollo command. * - * @param the sender type - * @since 1.0.9 + * @since 1.0.5 */ -public abstract class BungeeApolloCommand extends AbstractApolloCommand { +public final class BungeeApolloCommand extends ApolloCommand { /** - * Returns a new instance of a Bungee command. + * Returns a new instance of this command. * - * @param textConsumer the consumer for sending messages to the sender - * @since 1.0.9 + * @return a new command + * @since 1.0.5 */ - public BungeeApolloCommand(BiConsumer textConsumer) { - super(textConsumer); + public static Command create() { + return new Command("apollo", "apollo.command") { + private final BungeeApolloCommand command = new BungeeApolloCommand(); + + @Override + public void execute(CommandSender sender, String[] args) { + this.command.execute(sender, args); + } + }; } - /** - * Handles a player argument; if the provided player doesn't exist, a not found message - * is sent to the sender. Otherwise, the player is passed to the provided player consumer. - * - * @param sender the command sender - * @param argument the argument passed from the command execution - * @param playerConsumer a consumer used for processing a desired action if the player is found - * @since 1.0.9 - */ - protected void handlePlayerArgument(@NonNull T sender, @NonNull String argument, @NonNull Consumer playerConsumer) { - ProxiedPlayer player = ProxyServer.getInstance().getPlayer(argument); + BungeeApolloCommand() { + super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); + } - if (player == null) { - this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) - .append(Component.text(argument, NamedTextColor.RED)) - .append(Component.text("' not found!", NamedTextColor.RED))); - return; + void execute(CommandSender sender, String[] args) { + if(args.length < 1) { + this.getCurrentVersion(sender); + } else if(args[0].equalsIgnoreCase("reload")) { + this.reloadConfiguration(sender); + } else if(args[0].equalsIgnoreCase("update")) { + ApolloManager.getVersionManager().forceUpdate( + ApolloPlatform.Platform.BUNGEE, + message -> this.textConsumer.accept(sender, message) + ); } - - playerConsumer.accept(player); } + } diff --git a/bungee/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java b/bungee/src/main/java/com/lunarclient/apollo/command/BungeeLunarClientCommand.java similarity index 61% rename from bungee/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java rename to bungee/src/main/java/com/lunarclient/apollo/command/BungeeLunarClientCommand.java index ca455e49..1471edab 100644 --- a/bungee/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java +++ b/bungee/src/main/java/com/lunarclient/apollo/command/BungeeLunarClientCommand.java @@ -21,14 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.lunarclient.apollo.command.impl; +package com.lunarclient.apollo.command; import com.lunarclient.apollo.Apollo; -import com.lunarclient.apollo.command.BungeeApolloCommand; +import com.lunarclient.apollo.command.type.LunarClientCommand; import com.lunarclient.apollo.common.ApolloComponent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Command; /** @@ -36,7 +38,7 @@ * * @since 1.0.9 */ -public final class LunarClientCommand extends BungeeApolloCommand { +public final class BungeeLunarClientCommand extends LunarClientCommand { /** * Returns a new instance of this command. @@ -46,7 +48,7 @@ public final class LunarClientCommand extends BungeeApolloCommand */ public static Command create() { return new Command("lunarclient", "apollo.lunarclient") { - private final LunarClientCommand command = new LunarClientCommand(); + private final BungeeLunarClientCommand command = new BungeeLunarClientCommand(); @Override public void execute(CommandSender sender, String[] args) { @@ -55,7 +57,7 @@ public void execute(CommandSender sender, String[] args) { }; } - LunarClientCommand() { + BungeeLunarClientCommand() { super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); this.setUsage("/lunarclient "); @@ -67,20 +69,27 @@ void execute(CommandSender sender, String[] args) { return; } - this.handlePlayerArgument(sender, args[0], player -> { - Component message = Component.text("Player ", NamedTextColor.GRAY) - .append(Component.text(player.getName(), NamedTextColor.AQUA)) - .append(Component.text(" is ", NamedTextColor.GRAY)); + ProxiedPlayer player = ProxyServer.getInstance().getPlayer(args[0]); - if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { - message = message.append(Component.text("using ", NamedTextColor.GREEN)); - } else { - message = message.append(Component.text("not using ", NamedTextColor.RED)); - } + if (player == null) { + this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) + .append(Component.text(args[0], NamedTextColor.RED)) + .append(Component.text("' not found!", NamedTextColor.RED))); + return; + } + + Component message = Component.text("Player ", NamedTextColor.GRAY) + .append(Component.text(player.getName(), NamedTextColor.AQUA)) + .append(Component.text(" is ", NamedTextColor.GRAY)); + + if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { + message = message.append(Component.text("using ", NamedTextColor.GREEN)); + } else { + message = message.append(Component.text("not using ", NamedTextColor.RED)); + } - message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); - this.textConsumer.accept(sender, message); - }); + message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); + this.textConsumer.accept(sender, message); } } diff --git a/bungee/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java b/bungee/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java deleted file mode 100644 index 57e56622..00000000 --- a/bungee/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of Apollo, licensed under the MIT License. - * - * Copyright (c) 2023 Moonsworth - * - * 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. - */ -package com.lunarclient.apollo.command.impl; - -import com.lunarclient.apollo.ApolloManager; -import com.lunarclient.apollo.command.BungeeApolloCommand; -import com.lunarclient.apollo.common.ApolloComponent; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.plugin.Command; - -/** - * The general Apollo command. - * - * @since 1.0.5 - */ -public final class ApolloCommand extends BungeeApolloCommand { - - /** - * Returns a new instance of this command. - * - * @return a new command - * @since 1.0.5 - */ - public static Command create() { - return new Command("apollo", "apollo.command") { - private final ApolloCommand command = new ApolloCommand(); - - @Override - public void execute(CommandSender sender, String[] args) { - this.command.execute(sender, args); - } - }; - } - - ApolloCommand() { - super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); - } - - void execute(CommandSender sender, String[] args) { - if(args.length < 1) { - this.getCurrentVersion(sender); - } else if(args[0].equalsIgnoreCase("reload")) { - this.reloadConfiguration(sender); - } else if(args[0].equalsIgnoreCase("update")) { - ApolloManager.getVersionManager().forceUpdate( - "bungee", - message -> this.textConsumer.accept(sender, message) - ); - } - } - -} diff --git a/common/src/main/java/com/lunarclient/apollo/api/ApolloHttpManager.java b/common/src/main/java/com/lunarclient/apollo/api/ApolloHttpManager.java index 1e222279..99365450 100644 --- a/common/src/main/java/com/lunarclient/apollo/api/ApolloHttpManager.java +++ b/common/src/main/java/com/lunarclient/apollo/api/ApolloHttpManager.java @@ -46,7 +46,7 @@ import org.jetbrains.annotations.Nullable; /** - * Manages Apollo http requests & responses. + * Manages Apollo http requests and responses. * * @since 1.0.0 */ diff --git a/common/src/main/java/com/lunarclient/apollo/api/request/ServerStartRequest.java b/common/src/main/java/com/lunarclient/apollo/api/request/ServerStartRequest.java index 3a23d670..c5b86e36 100644 --- a/common/src/main/java/com/lunarclient/apollo/api/request/ServerStartRequest.java +++ b/common/src/main/java/com/lunarclient/apollo/api/request/ServerStartRequest.java @@ -78,7 +78,7 @@ public final class ServerStartRequest implements ApiRequest private final String platformType; /** - * The platform subtype (Bukkit, Folia, BungeeCord, Velocity...). + * The platform subtype (Bukkit, Folia, Minestom, BungeeCord, Velocity...). * * @since 1.0.0 */ @@ -133,6 +133,13 @@ public final class ServerStartRequest implements ApiRequest */ private final List modules; + /** + * The current version of Apollo that is running. + * + * @since 1.2.0 + */ + private final String apolloVersion; + @Override public ApiServiceType getService() { return ApiServiceType.ANALYTICS; diff --git a/common/src/main/java/com/lunarclient/apollo/api/response/VersionResponse.java b/common/src/main/java/com/lunarclient/apollo/api/response/VersionResponse.java index 76fd9edc..ae861a27 100644 --- a/common/src/main/java/com/lunarclient/apollo/api/response/VersionResponse.java +++ b/common/src/main/java/com/lunarclient/apollo/api/response/VersionResponse.java @@ -90,6 +90,14 @@ public static final class Assets { */ String folia; + /** + * Returns the latest version of apollo {@link String} Minestom download URL. + * + * @return the apollo minestom download url + * @since 1.2.0 + */ + String minestom; + } } diff --git a/common/src/main/java/com/lunarclient/apollo/command/AbstractApolloCommand.java b/common/src/main/java/com/lunarclient/apollo/command/AbstractApolloCommand.java index 9769bf6d..67262529 100644 --- a/common/src/main/java/com/lunarclient/apollo/command/AbstractApolloCommand.java +++ b/common/src/main/java/com/lunarclient/apollo/command/AbstractApolloCommand.java @@ -23,11 +23,7 @@ */ package com.lunarclient.apollo.command; -import com.lunarclient.apollo.Apollo; -import com.lunarclient.apollo.ApolloManager; -import com.lunarclient.apollo.module.ApolloModuleManagerImpl; import java.util.function.BiConsumer; -import java.util.logging.Level; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -48,47 +44,6 @@ public abstract class AbstractApolloCommand { protected String usage; - /** - * Sends the current version message to the sender. - * - * @param sender the command sender - * @since 1.0.5 - */ - protected void getCurrentVersion(@NonNull T sender) { - this.textConsumer.accept(sender, Component.text("Apollo is running version ", NamedTextColor.GREEN) - .append(Component.text(Apollo.getPlatform().getApolloVersion(), NamedTextColor.WHITE)) - .append(Component.text(".", NamedTextColor.GREEN)) - ); - } - - /** - * Reloads the configuration and messages the result to the sender. - * - * @param sender the command sender - * @since 1.0.5 - */ - protected void reloadConfiguration(@NonNull T sender) { - try { - ApolloManager.loadConfiguration(); - ((ApolloModuleManagerImpl) Apollo.getModuleManager()).reloadModules(); - ApolloManager.saveConfiguration(); - } catch (Throwable throwable) { - Apollo.getPlatform().getPlatformLogger().log(Level.SEVERE, "Unable to save Apollo configuration!", throwable); - - this.textConsumer.accept(sender, Component.text( - "An error occurred attempting to save the configuration!", - NamedTextColor.RED - )); - - return; - } - - this.textConsumer.accept(sender, Component.text( - "Reloaded the Apollo configuration!", - NamedTextColor.GREEN - )); - } - /** * Sends the command usage to the sender. * diff --git a/common/src/main/java/com/lunarclient/apollo/command/type/ApolloCommand.java b/common/src/main/java/com/lunarclient/apollo/command/type/ApolloCommand.java new file mode 100644 index 00000000..a18bf323 --- /dev/null +++ b/common/src/main/java/com/lunarclient/apollo/command/type/ApolloCommand.java @@ -0,0 +1,95 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.command.type; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.command.AbstractApolloCommand; +import com.lunarclient.apollo.module.ApolloModuleManagerImpl; +import java.util.function.BiConsumer; +import java.util.logging.Level; +import lombok.NonNull; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; + +/** + * The general Apollo command. + * + * @param the sender type + * @since 1.2.0 + */ +public class ApolloCommand extends AbstractApolloCommand { + + /** + * Returns a new instance of the ApolloCommand. + * + * @param textConsumer the consumer for sending messages to the sender + * @since 1.2.0 + */ + protected ApolloCommand(BiConsumer textConsumer) { + super(textConsumer); + } + + /** + * Sends the current version message to the sender. + * + * @param sender the command sender + * @since 1.0.5 + */ + protected void getCurrentVersion(@NonNull T sender) { + this.textConsumer.accept(sender, Component.text("Apollo is running version ", NamedTextColor.GREEN) + .append(Component.text(Apollo.getPlatform().getApolloVersion(), NamedTextColor.WHITE)) + .append(Component.text(".", NamedTextColor.GREEN)) + ); + } + + /** + * Reloads the configuration and messages the result to the sender. + * + * @param sender the command sender + * @since 1.0.5 + */ + protected void reloadConfiguration(@NonNull T sender) { + try { + ApolloManager.loadConfiguration(); + ((ApolloModuleManagerImpl) Apollo.getModuleManager()).reloadModules(); + ApolloManager.saveConfiguration(); + } catch (Throwable throwable) { + Apollo.getPlatform().getPlatformLogger().log(Level.SEVERE, "Unable to save Apollo configuration!", throwable); + + this.textConsumer.accept(sender, Component.text( + "An error occurred attempting to save the configuration!", + NamedTextColor.RED + )); + + return; + } + + this.textConsumer.accept(sender, Component.text( + "Reloaded the Apollo configuration!", + NamedTextColor.GREEN + )); + } + +} diff --git a/bukkit/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java b/common/src/main/java/com/lunarclient/apollo/command/type/LunarClientCommand.java similarity index 51% rename from bukkit/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java rename to common/src/main/java/com/lunarclient/apollo/command/type/LunarClientCommand.java index 1285bf79..74ba54c3 100644 --- a/bukkit/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java +++ b/common/src/main/java/com/lunarclient/apollo/command/type/LunarClientCommand.java @@ -21,45 +21,28 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.lunarclient.apollo.command.impl; +package com.lunarclient.apollo.command.type; -import com.lunarclient.apollo.ApolloManager; -import com.lunarclient.apollo.command.BukkitApolloCommand; -import com.lunarclient.apollo.common.ApolloComponent; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import com.lunarclient.apollo.command.AbstractApolloCommand; +import java.util.function.BiConsumer; +import net.kyori.adventure.text.Component; /** - * The general Apollo command. + * The general Lunar Client command. * - * @since 1.0.5 + * @param the sender type + * @since 1.2.0 */ -public final class ApolloCommand extends BukkitApolloCommand implements CommandExecutor { +public class LunarClientCommand extends AbstractApolloCommand { /** - * Returns a new instance of this command. + * Returns a new instance of the LunarClientCommand. * - * @since 1.0.5 + * @param textConsumer the consumer for sending messages to the sender + * @since 1.2.0 */ - public ApolloCommand() { - super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if(args.length < 1) { - this.getCurrentVersion(sender); - } else if(args[0].equalsIgnoreCase("reload")) { - this.reloadConfiguration(sender); - } else if(args[0].equalsIgnoreCase("update")) { - ApolloManager.getVersionManager().forceUpdate( - "bukkit", - message -> this.textConsumer.accept(sender, message) - ); - } - - return true; + protected LunarClientCommand(BiConsumer textConsumer) { + super(textConsumer); } } diff --git a/common/src/main/java/com/lunarclient/apollo/stats/ApolloStatsManager.java b/common/src/main/java/com/lunarclient/apollo/stats/ApolloStatsManager.java index ad51fc36..ba8da86f 100644 --- a/common/src/main/java/com/lunarclient/apollo/stats/ApolloStatsManager.java +++ b/common/src/main/java/com/lunarclient/apollo/stats/ApolloStatsManager.java @@ -153,7 +153,8 @@ private void handleServerStartStats() { .platformType(platform.getKind().name()) .platformSubtype(stats.getPlatformSubtype()) .platformVersion(stats.getPlatformVersion()) - .modules(enabledModules); + .modules(enabledModules) + .apolloVersion(platform.getApolloVersion()); } if (softwareInformation) { diff --git a/common/src/main/java/com/lunarclient/apollo/version/ApolloVersion.java b/common/src/main/java/com/lunarclient/apollo/version/ApolloVersion.java index b25d80c8..9d9b6868 100644 --- a/common/src/main/java/com/lunarclient/apollo/version/ApolloVersion.java +++ b/common/src/main/java/com/lunarclient/apollo/version/ApolloVersion.java @@ -41,7 +41,7 @@ public class ApolloVersion { * Constructs the {@link ApolloVersion} by the * provided version string. * - *

Divides the version string by the major, minor & patch version.

+ *

Divides the version string by the major, minor and patch version.

* * @param version the version * @since 1.0.0 @@ -75,8 +75,14 @@ public ApolloVersion(String version) { public boolean isUpdateAvailable(ApolloVersion version) { if (version.getMajor() > this.major) { return true; - } else if (version.getMinor() > this.minor) { + } else if (version.getMajor() < this.major) { + return false; + } + + if (version.getMinor() > this.minor) { return true; + } else if (version.getMinor() < this.minor) { + return false; } return version.getPatch() > this.patch; diff --git a/common/src/main/java/com/lunarclient/apollo/version/ApolloVersionManager.java b/common/src/main/java/com/lunarclient/apollo/version/ApolloVersionManager.java index 4b6e2b0a..d13b6ce3 100644 --- a/common/src/main/java/com/lunarclient/apollo/version/ApolloVersionManager.java +++ b/common/src/main/java/com/lunarclient/apollo/version/ApolloVersionManager.java @@ -39,6 +39,8 @@ import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import java.util.logging.Logger; +import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -54,18 +56,9 @@ public final class ApolloVersionManager { .node("send-updater-message").type(TypeToken.get(Boolean.class)) .defaultValue(true).build(); - public static final String UPDATE_MESSAGE = "[Apollo] You're running an outdated version of Apollo. " + - "Use \"/apollo update\" to update to the latest version!"; + @Getter private VersionResponse updateAssets; - /** - * Returns whether the server needs to update Apollo. - * - * @since 1.0.0 - */ - public static boolean NEEDS_UPDATE; - - private VersionResponse.Assets assets; - private AtomicBoolean updated = new AtomicBoolean(false); + private final AtomicBoolean updated = new AtomicBoolean(false); /** * Constructs the {@link ApolloVersionManager}. @@ -84,18 +77,28 @@ public ApolloVersionManager() { public void checkForUpdates() { ApolloManager.getHttpManager().request(VersionRequest.builder().build()) .onSuccess(response -> { - this.assets = response.getAssets(); - ApolloPlatform platform = Apollo.getPlatform(); + String version = response.getVersion(); + ApolloVersion currentVersion = new ApolloVersion(platform.getApolloVersion()); - ApolloVersion latestVersion = new ApolloVersion(response.getVersion()); + ApolloVersion latestVersion = new ApolloVersion(version); - if (currentVersion.isUpdateAvailable(latestVersion)) { - ApolloVersionManager.NEEDS_UPDATE = true; + if (!currentVersion.isUpdateAvailable(latestVersion)) { + return; + } - if (platform.getOptions().get(ApolloVersionManager.SEND_UPDATE_MESSAGE)) { - platform.getPlatformLogger().warning(UPDATE_MESSAGE); - } + this.updateAssets = response; + + if (!platform.getOptions().get(ApolloVersionManager.SEND_UPDATE_MESSAGE)) { + return; + } + + Logger logger = platform.getPlatformLogger(); + logger.warning(String.format("A new version of Apollo is available! Latest release: %s", version)); + + if (platform.getPlatform() != ApolloPlatform.Platform.MINESTOM) { + logger.warning("Please update by running \"/apollo update\" or by downloading the " + + "latest build from https://lunarclient.dev/apollo/downloads"); } }) .onFailure(Throwable::printStackTrace); @@ -108,7 +111,7 @@ public void checkForUpdates() { * @param message the message to send to the command sender * @since 1.0.9 */ - public void forceUpdate(String platform, Consumer message) { + public void forceUpdate(ApolloPlatform.Platform platform, Consumer message) { if (this.updated.get()) { message.accept(Component.text( "Apollo is already updated, please restart your server!", @@ -117,7 +120,7 @@ public void forceUpdate(String platform, Consumer message) { return; } - if (!ApolloVersionManager.NEEDS_UPDATE) { + if (this.updateAssets == null) { message.accept(Component.text( "This server is already running the latest version of Apollo.", NamedTextColor.RED) @@ -125,7 +128,8 @@ public void forceUpdate(String platform, Consumer message) { return; } - if (this.assets == null) { + String downloadUrl = this.getPlatformUrl(platform); + if (downloadUrl == null) { message.accept(Component.text( "Unable to find assets to update from.", NamedTextColor.RED) @@ -133,15 +137,6 @@ public void forceUpdate(String platform, Consumer message) { return; } - String platformUrl = this.getPlatformUrl(platform); - if (platformUrl == null) { - message.accept(Component.text( - "Unable to find platform url.", - NamedTextColor.RED) - ); - return; - } - // Find the current running Apollo jar URL url = Apollo.getPlatform().getPlugin() .getClass() @@ -158,14 +153,14 @@ public void forceUpdate(String platform, Consumer message) { } // Find name of the new Apollo jar - String[] urlArgs = platformUrl.split("/"); + String[] urlArgs = downloadUrl.split("/"); String fileName = urlArgs[urlArgs.length - 1]; // Create a path for the downloaded Apollo jar Path updatedJarPath = Paths.get(file.getParent() + File.separator + fileName); DownloadFileRequest request = DownloadFileRequest.builder() - .url(platformUrl) + .url(downloadUrl) .target(updatedJarPath) .build(); @@ -190,22 +185,24 @@ public void forceUpdate(String platform, Consumer message) { }); } - private String getPlatformUrl(String platform) { - switch (platform.toLowerCase()) { - case "bukkit": { - return this.assets.getBukkit(); + private String getPlatformUrl(ApolloPlatform.Platform platform) { + VersionResponse.Assets assets = this.updateAssets.getAssets(); + + switch (platform) { + case BUKKIT: { + return assets.getBukkit(); } - case "bungee": { - return this.assets.getBungee(); + case BUNGEE: { + return assets.getBungee(); } - case "velocity": { - return this.assets.getVelocity(); + case VELOCITY: { + return assets.getVelocity(); } - case "folia": { - return this.assets.getFolia(); + case FOLIA: { + return assets.getFolia(); } } diff --git a/docs/developers/_meta.json b/docs/developers/_meta.json index 9a1ca48a..f6f66360 100644 --- a/docs/developers/_meta.json +++ b/docs/developers/_meta.json @@ -8,5 +8,6 @@ "utilities": "Utilities", "platform-utilities": "Platform Utilities", "adventure": "Adventure", + "minestom": "Minestom", "lightweight": "Lightweight" } diff --git a/docs/developers/minestom.mdx b/docs/developers/minestom.mdx new file mode 100644 index 00000000..bf26ef88 --- /dev/null +++ b/docs/developers/minestom.mdx @@ -0,0 +1,228 @@ +import { Tab, Tabs } from 'nextra-theme-docs'; +import { Callout } from 'nextra-theme-docs' + +# Apollo for Minestom + +[Minestom](https://minestom.net/) is a modern, open-source Minecraft server that enables developers to build highly performant and flexible servers from the ground up. It operates as a library, rather than relying on a traditional plugin-based architecture. + +Integrating Apollo with your Minestom server is straightforward. Instead of installing a plugin, you'll simply add the `apollo-minestom` artifact as a library dependency to your project and initialize the `ApolloMinestomPlatform` within your server's startup sequence. + +## Adding the Repository + +First, you need to add the Lunar Client Maven repository to your build configuration. + + + + ```kotlin filename="build.gradle.kts" + repositories { + maven { + name = "lunarclient" + url = uri("https://repo.lunarclient.dev") + } + } + ``` + + + ```groovy filename="build.gradle" + repositories { + maven { + name = 'lunarclient' + url = 'https://repo.lunarclient.dev' + } + } + ``` + + + ```xml filename="pom.xml" + + + lunarclient + https://repo.lunarclient.dev + + + ``` + + + +## Adding the Dependency + +Next, add the `apollo-minestom` dependency to your project. + + + + ```kotlin filename="build.gradle.kts" + dependencies { + implementation("com.lunarclient:apollo-minestom:1.2.0") + } + ``` + + + ```groovy filename="build.gradle" + dependencies { + implementation 'com.lunarclient:apollo-minestom:1.2.0' + } + ``` + + + ```xml filename="pom.xml" + + + com.lunarclient + apollo-minestom + 1.2.0 + compile + + + ``` + + + +## Initialization + +To initialize Apollo, simply call `ApolloMinestomPlatform.init(ApolloMinestomProperties.DEFAULT_PROPERTIES)` in your server's startup code, before you start the server. This will set up all the necessary listeners and modules. + +Here is an example of a simple Minestom server with Apollo integrated: + +```java filename="ApolloMinestomExample.java" +package com.lunarclient.apollo.example; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.ApolloMinestomPlatform; +import com.lunarclient.apollo.ApolloMinestomProperties; +import com.lunarclient.apollo.common.location.ApolloBlockLocation; +import com.lunarclient.apollo.event.EventBus; +import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent; +import com.lunarclient.apollo.module.waypoint.Waypoint; +import com.lunarclient.apollo.module.waypoint.WaypointModule; +import com.lunarclient.apollo.player.ApolloPlayer; +import java.awt.Color; +import net.minestom.server.Auth; +import net.minestom.server.MinecraftServer; +import net.minestom.server.event.GlobalEventHandler; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; +import net.minestom.server.instance.InstanceContainer; +import net.minestom.server.instance.block.Block; + +public final class ApolloMinestomExample { + + public static void main(String[] args) { + MinecraftServer server = MinecraftServer.init(new Auth.Online()); + + InstanceContainer instance = MinecraftServer.getInstanceManager().createInstanceContainer(); + instance.setGenerator(unit -> unit.modifier().fillHeight(-1, 0, Block.STONE)); + + GlobalEventHandler eventHandler = MinecraftServer.getGlobalEventHandler(); + eventHandler.addListener(AsyncPlayerConfigurationEvent.class, event -> event.setSpawningInstance(instance)); + + // Initialize Apollo + ApolloMinestomPlatform.init(ApolloMinestomProperties.DEFAULT_PROPERTIES); + + // Display a Apollo Waypoint example + EventBus.getBus().register(ApolloRegisterPlayerEvent.class, event -> { + ApolloPlayer player = event.getPlayer(); + + Apollo.getModuleManager().getModule(WaypointModule.class).displayWaypoint(player, Waypoint.builder() + .name("KoTH") + .location(ApolloBlockLocation.builder() + .world(player.getWorld().get().getName()) + .x(500) + .y(100) + .z(500) + .build()) + .color(Color.ORANGE) + .preventRemoval(false) + .hidden(false) + .build() + ); + }); + + server.start("0.0.0.0", 25565); + } + + private ApolloMinestomExample() { + } + +} +``` + +## Configuration + +You can customize Apollo's behavior by passing a configured `ApolloMinestomProperties` object during initialization. While `ApolloMinestomProperties.DEFAULT_PROPERTIES` is sufficient for most use cases, you can tailor the settings to your server's specific needs. + +Here’s an overview of the available properties and how to use them. + +### Properties + +These properties control the core functionalities of Apollo on the Minestom platform. + +#### `sendRegisterPacket` +- **Default:** `true` +- **Description:** Controls whether Apollo should send the `minecraft:register` packet for its plugin channel (`lunar:apollo`). Unlike other server platforms, Minestom does not manage a global registry of plugin channels, so this step is necessary for the client to recognize Apollo. + + + If you disable this, you are responsible for registering the `lunar:apollo` channel manually. Failure to do so will prevent Apollo from communicating with clients. + + +```java +ApolloMinestomProperties.builder() + .sendRegisterPacket(false) + .build() +``` + +#### `configPath` +- **Default:** `./Apollo/` +- **Description:** Specifies the directory where Apollo's configuration files are stored. By default, it creates an `Apollo` folder in your server's root directory. You can change this to integrate with your existing configuration structure. + +```java +ApolloMinestomProperties.builder() + .configPath(Path.of("your/custom/config/path")) + .build() +``` + +### Commands + +Apollo's in-game commands can be fine-tuned using the `commandProperties` builder. This allows you to disable commands or integrate with your own permissions system. + +Since Minestom lacks a traditional, unified permissions API, Apollo provides a flexible predicate-based system. By **default**, it relies on Minestom's built-in operator permission levels. + +- Execute Commands (`/apollo`, `/lunarclient`): `2` +- Receive `Apollo Available Update` notifications: `4` + +**Disabling Commands** +```java +ApolloMinestomPlatform.init(ApolloMinestomProperties.builder() + .commandProperties(ApolloMinestomProperties.CommandProperties.builder() + .registerApolloCommand(false) + .registerLunarClientCommand(false) + .build() + ) + .build()); +) +``` + +**Custom Permissions** +```java +ApolloMinestomPlatform.init(ApolloMinestomProperties.builder() + .commandProperties(ApolloMinestomProperties.CommandProperties.builder() + .apolloCommandPermission(sender -> sender.hasPermissionLevel(4)) + .lunarClientCommandPermission(sender -> sender.hasPermissionLevel(1)) + .build() + ) + .build()); +) +``` + +### Complete Example + +Here is an example of a complete initialization call with custom properties: + +```java +ApolloMinestomPlatform.init(ApolloMinestomProperties.builder() + .sendRegisterPacket(false) + .configPath(Path.of("server-configs/apollo")) + .commandProperties(ApolloMinestomProperties.CommandProperties.builder() + .registerLunarClientCommand(false) + .apolloCommandPermission(sender -> sender.hasPermissionLevel(4)) + .build()) + .build()); +``` diff --git a/docs/developers/platform-utilities.mdx b/docs/developers/platform-utilities.mdx index 83d3b9ee..43fc6735 100644 --- a/docs/developers/platform-utilities.mdx +++ b/docs/developers/platform-utilities.mdx @@ -4,7 +4,7 @@ import { Callout } from 'nextra-theme-docs'; Platform utility classes provide helpful platform specific methods to improve your experience when creating an Apollo integration. -The following utility classes are available for each respective platform: `BukkitApollo`, `FoliaApollo`, `BungeeApollo`, `VelocityApollo` +The following utility classes are available for each respective platform: `BukkitApollo`, `FoliaApollo`, `MinestomApollo`, `BungeeApollo`, `VelocityApollo` You must ensure these methods are only used on the platform they're intended for, otherwise you will encounter errors from missing diff --git a/docs/downloads.mdx b/docs/downloads.mdx index afb6532a..88a080ee 100644 --- a/docs/downloads.mdx +++ b/docs/downloads.mdx @@ -2,7 +2,7 @@ import { faWindows } from "@fortawesome/free-brands-svg-icons/faWindows"; import { faDiscord } from "@fortawesome/free-brands-svg-icons/faDiscord"; import { faDownload } from "@fortawesome/free-solid-svg-icons/faDownload"; import { faQuestion } from "@fortawesome/free-solid-svg-icons/faQuestion"; -import { faBullhorn } from "@fortawesome/free-solid-svg-icons/faBullhorn"; +import { faFileCode } from "@fortawesome/free-solid-svg-icons/faFileCode"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Text } from "@moonsworth/text"; import router from "next/router"; @@ -66,11 +66,11 @@ import styles from "./downloads.module.css";
- Sponge - Sponge -
diff --git a/docs/public/minestom.png b/docs/public/minestom.png new file mode 100644 index 00000000..78930585 Binary files /dev/null and b/docs/public/minestom.png differ diff --git a/example/minestom/api/build.gradle.kts b/example/minestom/api/build.gradle.kts new file mode 100644 index 00000000..cec9d51e --- /dev/null +++ b/example/minestom/api/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + id("apollo.base-conventions") + id("apollo.shadow-conventions") +} + +java { + javaTarget(21) +} + +dependencies { + compileOnly(project(path = ":apollo-api", configuration = "minestom")) + implementation(project(path = ":apollo-minestom", configuration = "shadow")) + + implementation(libs.minestom) +} + +tasks { + jar { + manifest { + attributes["Main-Class"] = "com.lunarclient.apollo.example.ApolloMinestomExample" + } + } +} diff --git a/example/minestom/api/src/main/java/com/lunarclient/apollo/example/ApolloMinestomExample.java b/example/minestom/api/src/main/java/com/lunarclient/apollo/example/ApolloMinestomExample.java new file mode 100644 index 00000000..abb0407d --- /dev/null +++ b/example/minestom/api/src/main/java/com/lunarclient/apollo/example/ApolloMinestomExample.java @@ -0,0 +1,90 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.example; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.ApolloMinestomPlatform; +import com.lunarclient.apollo.ApolloMinestomProperties; +import com.lunarclient.apollo.common.location.ApolloBlockLocation; +import com.lunarclient.apollo.event.EventBus; +import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent; +import com.lunarclient.apollo.module.waypoint.Waypoint; +import com.lunarclient.apollo.module.waypoint.WaypointModule; +import com.lunarclient.apollo.player.ApolloPlayer; +import java.awt.Color; +import net.minestom.server.Auth; +import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.GameMode; +import net.minestom.server.entity.Player; +import net.minestom.server.event.GlobalEventHandler; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; +import net.minestom.server.event.player.PlayerSpawnEvent; +import net.minestom.server.instance.InstanceContainer; +import net.minestom.server.instance.block.Block; + +public final class ApolloMinestomExample { + + public static void main(String[] args) { + MinecraftServer server = MinecraftServer.init(new Auth.Online()); + + InstanceContainer instance = MinecraftServer.getInstanceManager().createInstanceContainer(); + instance.setGenerator(unit -> unit.modifier().fillHeight(-1, 0, Block.STONE)); + + GlobalEventHandler eventHandler = MinecraftServer.getGlobalEventHandler(); + eventHandler.addListener(AsyncPlayerConfigurationEvent.class, event -> event.setSpawningInstance(instance)); + eventHandler.addListener(PlayerSpawnEvent.class, event -> { + Player player = event.getPlayer(); + player.setPermissionLevel(4); + player.setGameMode(GameMode.CREATIVE); + }); + + // Initialize Apollo + ApolloMinestomPlatform.init(ApolloMinestomProperties.DEFAULT_PROPERTIES); + + // Display a Apollo Waypoint example + EventBus.getBus().register(ApolloRegisterPlayerEvent.class, event -> { + ApolloPlayer player = event.getPlayer(); + + Apollo.getModuleManager().getModule(WaypointModule.class).displayWaypoint(player, Waypoint.builder() + .name("KoTH") + .location(ApolloBlockLocation.builder() + .world(player.getWorld().get().getName()) + .x(500) + .y(100) + .z(500) + .build()) + .color(Color.ORANGE) + .preventRemoval(false) + .hidden(false) + .build() + ); + }); + + server.start("0.0.0.0", 25565); + } + + private ApolloMinestomExample() { + } + +} diff --git a/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java b/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java index f72e0e61..504fae76 100644 --- a/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java +++ b/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java @@ -23,8 +23,8 @@ */ package com.lunarclient.apollo; -import com.lunarclient.apollo.command.impl.ApolloCommand; -import com.lunarclient.apollo.command.impl.LunarClientCommand; +import com.lunarclient.apollo.command.FoliaApolloCommand; +import com.lunarclient.apollo.command.FoliaLunarClientCommand; import com.lunarclient.apollo.listener.ApolloMetadataListener; import com.lunarclient.apollo.listener.ApolloPlayerListener; import com.lunarclient.apollo.listener.ApolloWorldListener; @@ -161,8 +161,8 @@ public void onEnable() { (channel, player, bytes) -> ApolloManager.getNetworkManager().receivePacket(player.getUniqueId(), bytes) ); - this.getCommand("apollo").setExecutor(new ApolloCommand()); - this.getCommand("lunarclient").setExecutor(new LunarClientCommand()); + this.getCommand("apollo").setExecutor(new FoliaApolloCommand()); + this.getCommand("lunarclient").setExecutor(new FoliaLunarClientCommand()); ApolloManager.getStatsManager().enable(); ApolloManager.getVersionManager().checkForUpdates(); @@ -178,6 +178,11 @@ public Kind getKind() { return Kind.SERVER; } + @Override + public Platform getPlatform() { + return Platform.FOLIA; + } + @Override public String getApolloVersion() { return this.getDescription().getVersion(); diff --git a/folia/src/main/java/com/lunarclient/apollo/command/FoliaApolloCommand.java b/folia/src/main/java/com/lunarclient/apollo/command/FoliaApolloCommand.java index 7567e5cf..b4fd4b57 100644 --- a/folia/src/main/java/com/lunarclient/apollo/command/FoliaApolloCommand.java +++ b/folia/src/main/java/com/lunarclient/apollo/command/FoliaApolloCommand.java @@ -23,51 +23,45 @@ */ package com.lunarclient.apollo.command; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import lombok.NonNull; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.ApolloPlatform; +import com.lunarclient.apollo.command.type.ApolloCommand; +import com.lunarclient.apollo.common.ApolloComponent; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; /** - * Provides common command functions for Folia. + * The general Apollo command. * - * @param the sender type * @since 1.1.8 */ -public abstract class FoliaApolloCommand extends AbstractApolloCommand { +public final class FoliaApolloCommand extends ApolloCommand implements CommandExecutor { /** - * Returns a new instance of a Folia command. + * Returns a new instance of this command. * - * @param textConsumer the consumer for sending messages to the sender * @since 1.1.8 */ - public FoliaApolloCommand(BiConsumer textConsumer) { - super(textConsumer); + public FoliaApolloCommand() { + super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); } - /** - * Handles a player argument; if the provided player doesn't exist, a not found message - * is sent to the sender. Otherwise, the player is passed to the provided player consumer. - * - * @param sender the command sender - * @param argument the argument passed from the command execution - * @param playerConsumer a consumer used for processing a desired action if the player is found - * @since 1.1.8 - */ - protected void handlePlayerArgument(@NonNull T sender, @NonNull String argument, @NonNull Consumer playerConsumer) { - Player player = Bukkit.getPlayer(argument); - - if (player == null) { - this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) - .append(Component.text(argument, NamedTextColor.RED)) - .append(Component.text("' not found!", NamedTextColor.RED))); - return; + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + if(args.length < 1) { + this.getCurrentVersion(sender); + } else if(args[0].equalsIgnoreCase("reload")) { + this.reloadConfiguration(sender); + } else if(args[0].equalsIgnoreCase("update")) { + ApolloManager.getVersionManager().forceUpdate( + ApolloPlatform.Platform.FOLIA, + message -> this.textConsumer.accept(sender, message) + ); } - playerConsumer.accept(player); + return true; } + } diff --git a/folia/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java b/folia/src/main/java/com/lunarclient/apollo/command/FoliaLunarClientCommand.java similarity index 55% rename from folia/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java rename to folia/src/main/java/com/lunarclient/apollo/command/FoliaLunarClientCommand.java index 98c6aaff..f44da0cf 100644 --- a/folia/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java +++ b/folia/src/main/java/com/lunarclient/apollo/command/FoliaLunarClientCommand.java @@ -21,56 +21,66 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.lunarclient.apollo.command.impl; +package com.lunarclient.apollo.command; import com.lunarclient.apollo.Apollo; -import com.lunarclient.apollo.command.FoliaApolloCommand; +import com.lunarclient.apollo.command.type.LunarClientCommand; import com.lunarclient.apollo.common.ApolloComponent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; /** * The general Lunar Client command. * * @since 1.1.8 */ -public final class LunarClientCommand extends FoliaApolloCommand implements CommandExecutor { +public final class FoliaLunarClientCommand extends LunarClientCommand implements CommandExecutor { /** * Returns a new instance of this command. * * @since 1.1.8 */ - public LunarClientCommand() { + public FoliaLunarClientCommand() { super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); this.setUsage("/lunarclient "); } @Override - public boolean onCommand(CommandSender commandSender, Command command, String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { if(args.length != 1) { - this.sendCommandUsage(commandSender); + this.sendCommandUsage(sender); return true; } - this.handlePlayerArgument(commandSender, args[0], player -> { - Component message = Component.text("Player ", NamedTextColor.GRAY) - .append(Component.text(player.getName(), NamedTextColor.AQUA)) - .append(Component.text(" is ", NamedTextColor.GRAY)); + Player player = Bukkit.getPlayer(args[0]); - if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { - message = message.append(Component.text("using ", NamedTextColor.GREEN)); - } else { - message = message.append(Component.text("not using ", NamedTextColor.RED)); - } + if (player == null) { + this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) + .append(Component.text(args[0], NamedTextColor.RED)) + .append(Component.text("' not found!", NamedTextColor.RED))); + return true; + } + + Component message = Component.text("Player ", NamedTextColor.GRAY) + .append(Component.text(player.getName(), NamedTextColor.AQUA)) + .append(Component.text(" is ", NamedTextColor.GRAY)); + + if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { + message = message.append(Component.text("using ", NamedTextColor.GREEN)); + } else { + message = message.append(Component.text("not using ", NamedTextColor.RED)); + } - message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); - this.textConsumer.accept(commandSender, message); - }); + message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); + this.textConsumer.accept(sender, message); return true; } diff --git a/folia/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java b/folia/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java index 8c2c7fd3..c25f6db9 100644 --- a/folia/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java +++ b/folia/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java @@ -25,6 +25,7 @@ import com.lunarclient.apollo.Apollo; import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.api.response.VersionResponse; import com.lunarclient.apollo.event.ApolloListener; import com.lunarclient.apollo.event.ApolloReceivePacketEvent; import com.lunarclient.apollo.event.EventBus; @@ -33,8 +34,9 @@ import com.lunarclient.apollo.player.v1.PlayerHandshakeMessage; import com.lunarclient.apollo.version.ApolloVersionManager; import com.lunarclient.apollo.wrapper.FoliaApolloPlayer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -87,13 +89,27 @@ private void onPlayerQuit(PlayerQuitEvent event) { @EventHandler private void onPlayerJoin(PlayerJoinEvent event) { - if (!ApolloVersionManager.NEEDS_UPDATE) { + VersionResponse updateAssets = ApolloManager.getVersionManager().getUpdateAssets(); + if (updateAssets == null) { + return; + } + + if (!Apollo.getPlatform().getOptions().get(ApolloVersionManager.SEND_UPDATE_MESSAGE)) { return; } Player player = event.getPlayer(); - if (player.isOp()) { - player.sendMessage(ChatColor.YELLOW + ApolloVersionManager.UPDATE_MESSAGE); + String version = updateAssets.getVersion(); + + if (version != null && player.isOp()) { + Component message = Component.text("[Apollo] A new version of Apollo is available! Latest release: ", NamedTextColor.YELLOW) + .append(Component.text(version, NamedTextColor.GOLD)) + .append(Component.text(" Please update by running ", NamedTextColor.YELLOW)) + .append(Component.text("/apollo update ", NamedTextColor.GOLD)) + .append(Component.text("or by downloading the latest build from ", NamedTextColor.YELLOW)) + .append(Component.text("https://lunarclient.dev/apollo/downloads", NamedTextColor.GOLD)); + + player.sendMessage(message); } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c195905..6193298e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,7 @@ spotless = "6.13.0" velocity = "3.3.0-SNAPSHOT" folia = "1.20.1-R0.1-SNAPSHOT" asm = "9.7.1" +minestom = "2025.08.18-1.21.8" [libraries] jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains" } @@ -53,6 +54,9 @@ bungee = { module = "net.md-5:bungeecord-api", version.ref = "bungee" } # velocity velocity = { module = "com.velocitypowered:velocity-api", version.ref = "velocity" } +# minestom +minestom = { module = "net.minestom:minestom", version.ref = "minestom" } + # build artifactregistry = { module = "gradle.plugin.com.google.cloud.artifactregistry:artifactregistry-gradle-plugin", version.ref = "artifactregistry" } spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" } diff --git a/minestom/build.gradle.kts b/minestom/build.gradle.kts new file mode 100644 index 00000000..27bc8e10 --- /dev/null +++ b/minestom/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + id("apollo.shadow-conventions") + id("apollo.publish-conventions") +} + +java { + javaTarget(21) +} + +dependencies { + compileOnly(libs.minestom) + compileOnly(libs.protobuf) + + api(project(path = ":apollo-api", configuration = "shadow")) + api(project(path = ":apollo-common", configuration = "shadow")) + + api(project(":extra:apollo-extra-adventure4")) + + annotationProcessor(libs.minestom) +} + +publishShadowJar() diff --git a/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java b/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java new file mode 100644 index 00000000..49cc2761 --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java @@ -0,0 +1,253 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo; + +import com.lunarclient.apollo.command.MinestomApolloCommand; +import com.lunarclient.apollo.command.MinestomLunarClientCommand; +import com.lunarclient.apollo.listener.ApolloMetadataListener; +import com.lunarclient.apollo.listener.ApolloPlayerListener; +import com.lunarclient.apollo.listener.ApolloWorldListener; +import com.lunarclient.apollo.metadata.MinestomMetadataManager; +import com.lunarclient.apollo.module.ApolloModuleManagerImpl; +import com.lunarclient.apollo.module.autotexthotkey.AutoTextHotkeyModule; +import com.lunarclient.apollo.module.beam.BeamModule; +import com.lunarclient.apollo.module.beam.BeamModuleImpl; +import com.lunarclient.apollo.module.border.BorderModule; +import com.lunarclient.apollo.module.border.BorderModuleImpl; +import com.lunarclient.apollo.module.chat.ChatModule; +import com.lunarclient.apollo.module.chat.ChatModuleImpl; +import com.lunarclient.apollo.module.coloredfire.ColoredFireModule; +import com.lunarclient.apollo.module.coloredfire.ColoredFireModuleImpl; +import com.lunarclient.apollo.module.combat.CombatModule; +import com.lunarclient.apollo.module.cooldown.CooldownModule; +import com.lunarclient.apollo.module.cooldown.CooldownModuleImpl; +import com.lunarclient.apollo.module.entity.EntityModule; +import com.lunarclient.apollo.module.entity.EntityModuleImpl; +import com.lunarclient.apollo.module.glint.GlintModule; +import com.lunarclient.apollo.module.glow.GlowModule; +import com.lunarclient.apollo.module.glow.GlowModuleImpl; +import com.lunarclient.apollo.module.hologram.HologramModule; +import com.lunarclient.apollo.module.hologram.HologramModuleImpl; +import com.lunarclient.apollo.module.inventory.InventoryModule; +import com.lunarclient.apollo.module.limb.LimbModule; +import com.lunarclient.apollo.module.limb.LimbModuleImpl; +import com.lunarclient.apollo.module.modsetting.ModSettingModule; +import com.lunarclient.apollo.module.nametag.NametagModule; +import com.lunarclient.apollo.module.nametag.NametagModuleImpl; +import com.lunarclient.apollo.module.nickhider.NickHiderModule; +import com.lunarclient.apollo.module.nickhider.NickHiderModuleImpl; +import com.lunarclient.apollo.module.notification.NotificationModule; +import com.lunarclient.apollo.module.notification.NotificationModuleImpl; +import com.lunarclient.apollo.module.packetenrichment.PacketEnrichmentImpl; +import com.lunarclient.apollo.module.packetenrichment.PacketEnrichmentModule; +import com.lunarclient.apollo.module.richpresence.RichPresenceModule; +import com.lunarclient.apollo.module.richpresence.RichPresenceModuleImpl; +import com.lunarclient.apollo.module.saturation.SaturationModule; +import com.lunarclient.apollo.module.serverrule.ServerRuleModule; +import com.lunarclient.apollo.module.staffmod.StaffModModule; +import com.lunarclient.apollo.module.staffmod.StaffModModuleImpl; +import com.lunarclient.apollo.module.stopwatch.StopwatchModule; +import com.lunarclient.apollo.module.stopwatch.StopwatchModuleImpl; +import com.lunarclient.apollo.module.team.TeamModule; +import com.lunarclient.apollo.module.team.TeamModuleImpl; +import com.lunarclient.apollo.module.tebex.TebexModule; +import com.lunarclient.apollo.module.tebex.TebexModuleImpl; +import com.lunarclient.apollo.module.title.TitleModule; +import com.lunarclient.apollo.module.title.TitleModuleImpl; +import com.lunarclient.apollo.module.tntcountdown.TntCountdownModule; +import com.lunarclient.apollo.module.tntcountdown.TntCountdownModuleImpl; +import com.lunarclient.apollo.module.transfer.TransferModule; +import com.lunarclient.apollo.module.transfer.TransferModuleImpl; +import com.lunarclient.apollo.module.vignette.VignetteModule; +import com.lunarclient.apollo.module.vignette.VignetteModuleImpl; +import com.lunarclient.apollo.module.waypoint.WaypointModule; +import com.lunarclient.apollo.module.waypoint.WaypointModuleImpl; +import com.lunarclient.apollo.option.Options; +import com.lunarclient.apollo.option.OptionsImpl; +import com.lunarclient.apollo.stats.ApolloStats; +import com.lunarclient.apollo.wrapper.MinestomApolloStats; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import lombok.Getter; +import net.minestom.server.MinecraftServer; +import net.minestom.server.command.CommandManager; +import net.minestom.server.command.builder.Command; +import net.minestom.server.event.Event; +import net.minestom.server.event.EventNode; + +/** + * The Minestom platform plugin. + * + * @since 1.2.0 + */ +public final class ApolloMinestomPlatform implements ApolloPlatform { + + @Getter private static ApolloMinestomPlatform instance; + + private final Options options; + private final Logger logger; + private final ApolloStats stats; + @Getter private final ApolloMinestomProperties properties; + + /** + * Constructs the {@link ApolloMinestomPlatform}. + * + * @param properties the Apollo minestom properties + * @since 1.2.0 + */ + public ApolloMinestomPlatform(ApolloMinestomProperties properties) { + this.options = new OptionsImpl(null); + this.logger = Logger.getLogger(ApolloMinestomPlatform.class.getName()); + this.stats = new MinestomApolloStats(); + this.properties = properties; + } + + /** + * Initialize Apollo for Minestom. + * + * @param properties the Apollo minestom properties + * @since 1.2.0 + */ + public static void init(ApolloMinestomProperties properties) { + if (instance != null) { + throw new IllegalStateException("ApolloMinestomPlatform is already initialized!"); + } + + instance = new ApolloMinestomPlatform(properties); + + ApolloManager.bootstrap(instance); + ApolloManager.setMetadataManager(new MinestomMetadataManager()); + + EventNode node = EventNode.all("apollo"); + + new ApolloMetadataListener(node); + new ApolloPlayerListener(node); + new ApolloWorldListener(node); + + MinecraftServer.getGlobalEventHandler().addChild(node); + + ((ApolloModuleManagerImpl) Apollo.getModuleManager()) + .addModule(AutoTextHotkeyModule.class) + .addModule(BeamModule.class, new BeamModuleImpl()) + .addModule(BorderModule.class, new BorderModuleImpl()) + .addModule(ChatModule.class, new ChatModuleImpl()) + .addModule(ColoredFireModule.class, new ColoredFireModuleImpl()) + .addModule(CombatModule.class) + .addModule(CooldownModule.class, new CooldownModuleImpl()) + .addModule(EntityModule.class, new EntityModuleImpl()) + .addModule(GlintModule.class) + .addModule(GlowModule.class, new GlowModuleImpl()) + .addModule(HologramModule.class, new HologramModuleImpl()) + .addModule(InventoryModule.class) + .addModule(LimbModule.class, new LimbModuleImpl()) + .addModule(ModSettingModule.class) + .addModule(NametagModule.class, new NametagModuleImpl()) + .addModule(NickHiderModule.class, new NickHiderModuleImpl()) + .addModule(NotificationModule.class, new NotificationModuleImpl()) + .addModule(PacketEnrichmentModule.class, new PacketEnrichmentImpl()) + .addModule(RichPresenceModule.class, new RichPresenceModuleImpl()) + .addModule(SaturationModule.class) + .addModule(ServerRuleModule.class) + .addModule(StaffModModule.class, new StaffModModuleImpl()) + .addModule(StopwatchModule.class, new StopwatchModuleImpl()) + .addModule(TeamModule.class, new TeamModuleImpl()) + .addModule(TebexModule.class, new TebexModuleImpl()) + .addModule(TitleModule.class, new TitleModuleImpl()) + .addModule(TntCountdownModule.class, new TntCountdownModuleImpl()) + .addModule(TransferModule.class, new TransferModuleImpl()) + .addModule(VignetteModule.class, new VignetteModuleImpl()) + .addModule(WaypointModule.class, new WaypointModuleImpl()); + + try { + ApolloManager.setConfigPath(properties.getConfigPath()); + ApolloManager.loadConfiguration(); + ((ApolloModuleManagerImpl) Apollo.getModuleManager()).enableModules(); + ApolloManager.saveConfiguration(); + } catch (Throwable throwable) { + instance.getPlatformLogger().log(Level.SEVERE, "Unable to load Apollo configuration and modules!", throwable); + } + + ApolloMinestomPlatform.registerCommands(properties.getCommandProperties()); + + ApolloManager.getStatsManager().enable(); + ApolloManager.getVersionManager().checkForUpdates(); + + instance.getPlatformLogger().log(Level.INFO, "[Apollo] Successfully initialized! (" + instance.getApolloVersion() + ")"); + } + + private static void registerCommands(ApolloMinestomProperties.CommandProperties properties) { + Set commands = new HashSet<>(); + + if (properties.isRegisterApolloCommand()) { + commands.add(MinestomApolloCommand.create(properties.getApolloCommandPermission())); + } + + if (properties.isRegisterLunarClientCommand()) { + commands.add(MinestomLunarClientCommand.create(properties.getLunarClientCommandPermission())); + } + + CommandManager commandManager = MinecraftServer.getCommandManager(); + for (Command command : commands) { + commandManager.register(command); + } + } + + @Override + public Kind getKind() { + return Kind.SERVER; + } + + @Override + public Platform getPlatform() { + return Platform.MINESTOM; + } + + @Override + public Options getOptions() { + return this.options; + } + + @Override + public String getApolloVersion() { + return "1.2.0"; + } + + @Override + public ApolloStats getStats() { + return this.stats; + } + + @Override + public Logger getPlatformLogger() { + return this.logger; + } + + @Override + public Object getPlugin() { + return instance; + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomProperties.java b/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomProperties.java new file mode 100644 index 00000000..54e11913 --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomProperties.java @@ -0,0 +1,167 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Predicate; +import lombok.Builder; +import lombok.Getter; +import lombok.experimental.Accessors; +import net.minestom.server.command.CommandSender; +import net.minestom.server.entity.Player; + +/** + * Configuration properties for initializing the Apollo Minestom platform. + * + * @since 1.2.0 + */ +@Getter +@Builder +@Accessors +public class ApolloMinestomProperties { + + /** + * An instance of {@link ApolloMinestomProperties} with default properties. + */ + public static final ApolloMinestomProperties DEFAULT_PROPERTIES = ApolloMinestomProperties.builder().build(); + + /** + * Determines whether Apollo should skip sending the {@code minecraft:register} + * packet for its plugin channels. + * + *

By default, this is {@code false}, and Apollo will automatically register its + * {@code lunar:apollo} plugin channel to communicate with the client.

+ * + *

Set this to {@code true} if another plugin or system is responsible + * for sending the register packet, to avoid conflicts where + * multiple plugins attempt registration at the same time.

+ * + *

If you disable channel registration, you must ensure that your server + * or another plugin sends the {@code lunar:apollo} registration packet + * if you want Apollo to function correctly.

+ * + * @return true if channel registration is disabled, false otherwise + * @since 1.2.0 + */ + @Builder.Default + private final boolean sendRegisterPacket = true; + + /** + * The path where Apollo will store and load its configuration files. + * + *

By default, this path points to the {@code ./Apollo/} directory, + * relative to the server's working directory. If this directory does not + * exist, it will be created automatically.

+ * + *

Override this path if you want to keep Apollo's configuration files in a different location

+ * + * @return the path to Apollo's configuration directory + * @since 1.2.0 + */ + @Builder.Default + private final Path configPath = ApolloMinestomProperties.getDefaultConfigPath(); + + /** + * The command properties for Apollo Minestom. + * + * @return the command properties + * @since 1.2.0 + */ + @Builder.Default + private final CommandProperties commandProperties = CommandProperties.builder().build(); + + /** + * Computes the default configuration path ({@code ./Apollo/}). + * + * @return the resolved config path + * @since 1.2.0 + */ + private static Path getDefaultConfigPath() { + Path serverDir = Paths.get("").toAbsolutePath(); + Path apolloDir = serverDir.resolve("Apollo"); + File apolloFile = apolloDir.toFile(); + + if (!apolloFile.exists()) { + apolloFile.mkdirs(); + } + + return apolloDir; + } + + /** + * Configuration properties for Apollo commands on Minestom. + * + * @since 1.2.0 + */ + @Getter + @Builder + @Accessors + public static class CommandProperties { + + private static final Predicate DEFAULT_PERMISSION = sender -> + !(sender instanceof Player) || ((Player) sender).getPermissionLevel() >= 2; + + /** + * Determines whether Apollo should register the {@code /apollo} command. + * + * @return true if the command should be registered, false otherwise + * @since 1.2.0 + */ + @Builder.Default + private final boolean registerApolloCommand = true; + + /** + * Determines whether Apollo should register the {@code /lunarclient} command. + * + * @return true if the command should be registered, false otherwise + * @since 1.2.0 + */ + @Builder.Default + private final boolean registerLunarClientCommand = true; + + /** + * The predicate to check if a {@link CommandSender} has permission to use + * the {@code /apollo} command. + * + * @return the permission predicate + * @since 1.2.0 + */ + @Builder.Default + private final Predicate apolloCommandPermission = DEFAULT_PERMISSION; + + /** + * The predicate to check if a {@link CommandSender} has permission to use + * the {@code /lunarclient} command. + * + * @return the permission predicate + * @since 1.2.0 + */ + @Builder.Default + private final Predicate lunarClientCommandPermission = DEFAULT_PERMISSION; + + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/command/MinestomApolloCommand.java b/minestom/src/main/java/com/lunarclient/apollo/command/MinestomApolloCommand.java new file mode 100644 index 00000000..fd396aca --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/command/MinestomApolloCommand.java @@ -0,0 +1,92 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.command; + +import com.lunarclient.apollo.command.type.ApolloCommand; +import java.util.function.Predicate; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.command.CommandSender; +import net.minestom.server.command.builder.Command; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.command.builder.arguments.ArgumentWord; + +/** + * The Minestom implementation of the {@link ApolloCommand}. + * + * @since 1.2.0 + */ +public final class MinestomApolloCommand extends ApolloCommand { + + /** + * Returns a new instance of this command. + * + * @param permission the permission predicate + * @return a new command + * @since 1.2.0 + */ + public static Command create(Predicate permission) { + MinestomApolloCommand apolloCommand = new MinestomApolloCommand(); + + Command command = new Command("apollo"); + command.setDefaultExecutor((sender, context) -> { + if (!permission.test(sender)) { + sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); + return; + } + + apolloCommand.getCurrentVersion(sender); + }); + + ArgumentWord argument = ArgumentType.Word("action") + .from("reload", "update"); + + command.addSyntax((sender, context) -> { + if (!permission.test(sender)) { + sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); + return; + } + + String subArg = context.get(argument); + + if (subArg.equalsIgnoreCase("reload")) { + apolloCommand.reloadConfiguration(sender); + } else if (subArg.equalsIgnoreCase("update")) { + Component message = Component.text("[Apollo] The update command is not available for the ", NamedTextColor.YELLOW) + .append(Component.text("Minestom ", NamedTextColor.GOLD)) + .append(Component.text("platform!", NamedTextColor.YELLOW)); + + apolloCommand.textConsumer.accept(sender, message); + } + }, argument); + + return command; + } + + MinestomApolloCommand() { + super(Audience::sendMessage); + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/command/MinestomLunarClientCommand.java b/minestom/src/main/java/com/lunarclient/apollo/command/MinestomLunarClientCommand.java new file mode 100644 index 00000000..f652484e --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/command/MinestomLunarClientCommand.java @@ -0,0 +1,105 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.command; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.command.type.LunarClientCommand; +import java.util.function.Predicate; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.MinecraftServer; +import net.minestom.server.command.CommandSender; +import net.minestom.server.command.builder.Command; +import net.minestom.server.command.builder.arguments.ArgumentString; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.entity.Player; + +/** + * The general Lunar Client command. + * + * @since 1.2.0 + */ +public final class MinestomLunarClientCommand extends LunarClientCommand { + + /** + * Returns a new instance of this command. + * + * @param permission the permission predicate + * @return a new command + * @since 1.2.0 + */ + public static Command create(Predicate permission) { + MinestomLunarClientCommand lunarClientCommand = new MinestomLunarClientCommand(); + + Command command = new Command("lunarclient"); + command.setDefaultExecutor((sender, context) -> { + if (!permission.test(sender)) { + sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); + return; + } + + lunarClientCommand.sendCommandUsage(sender); + }); + + ArgumentString argument = ArgumentType.String("player"); + + command.addSyntax((sender, context) -> { + if (!permission.test(sender)) { + sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); + return; + } + + String playerName = context.get(argument); + Player player = MinecraftServer.getConnectionManager().getOnlinePlayerByUsername(playerName); + + if (player == null) { + lunarClientCommand.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) + .append(Component.text(playerName, NamedTextColor.RED)) + .append(Component.text("' not found!", NamedTextColor.RED))); + return; + } + + Component message = Component.text("Player ", NamedTextColor.GRAY) + .append(Component.text(player.getUsername(), NamedTextColor.AQUA)) + .append(Component.text(" is ", NamedTextColor.GRAY)); + + if (Apollo.getPlayerManager().hasSupport(player.getUuid())) { + message = message.append(Component.text("using ", NamedTextColor.GREEN)); + } else { + message = message.append(Component.text("not using ", NamedTextColor.RED)); + } + + message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); + lunarClientCommand.textConsumer.accept(sender, message); + }, argument); + + return command; + } + + MinestomLunarClientCommand() { + super(Audience::sendMessage); + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloMetadataListener.java b/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloMetadataListener.java new file mode 100644 index 00000000..10b108eb --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloMetadataListener.java @@ -0,0 +1,74 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.listener; + +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.metadata.MinestomMetadataManager; +import com.lunarclient.apollo.util.ByteBufUtil; +import java.nio.ByteBuffer; +import java.util.Map; +import net.minestom.server.event.Event; +import net.minestom.server.event.EventNode; +import net.minestom.server.event.player.PlayerPluginMessageEvent; +import net.minestom.server.event.player.PlayerResourcePackStatusEvent; + +/** + * Handles Apollo metadata listeners. + * + * @since 1.2.0 + */ +public final class ApolloMetadataListener { + + /** + * Constructs the {@link ApolloMetadataListener}. + * + * @param node the node + * @since 1.2.0 + */ + public ApolloMetadataListener(EventNode node) { + node.addListener(PlayerResourcePackStatusEvent.class, this::onResourcePackStatus); + node.addListener(PlayerPluginMessageEvent.class, this::onPlayerPluginMessage); + } + + private void onResourcePackStatus(PlayerResourcePackStatusEvent event) { + String status = event.getStatus().name(); + MinestomMetadataManager manager = (MinestomMetadataManager) ApolloManager.getMetadataManager(); + Map statuses = manager.getResourcePackStatuses(); + + statuses.put(status, statuses.getOrDefault(status, 0) + 1); + } + + private void onPlayerPluginMessage(PlayerPluginMessageEvent event) { + String identifier = event.getIdentifier(); + + if (!identifier.equals("minecraft:brand")) { + return; + } + + ByteBuffer buffer = ByteBuffer.wrap(event.getMessage()); + MinestomMetadataManager manager = (MinestomMetadataManager) ApolloManager.getMetadataManager(); + manager.getClientBrands().add(ByteBufUtil.readString(buffer)); + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java b/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java new file mode 100644 index 00000000..52dafce7 --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloPlayerListener.java @@ -0,0 +1,145 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.listener; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.ApolloMinestomPlatform; +import com.lunarclient.apollo.api.response.VersionResponse; +import com.lunarclient.apollo.event.ApolloListener; +import com.lunarclient.apollo.event.ApolloReceivePacketEvent; +import com.lunarclient.apollo.event.EventBus; +import com.lunarclient.apollo.event.Listen; +import com.lunarclient.apollo.player.ApolloPlayerManagerImpl; +import com.lunarclient.apollo.player.v1.PlayerHandshakeMessage; +import com.lunarclient.apollo.version.ApolloVersionManager; +import com.lunarclient.apollo.wrapper.MinestomApolloPlayer; +import java.util.Arrays; +import java.util.List; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.entity.Player; +import net.minestom.server.event.Event; +import net.minestom.server.event.EventNode; +import net.minestom.server.event.player.PlayerDisconnectEvent; +import net.minestom.server.event.player.PlayerPluginMessageEvent; +import net.minestom.server.event.player.PlayerSpawnEvent; + +/** + * Handles registration and un-registration of Apollo players. + * + * @since 1.2.0 + */ +public final class ApolloPlayerListener implements ApolloListener { + + /** + * Constructs the {@link ApolloPlayerListener}. + * + * @param node the node + * @since 1.2.0 + */ + public ApolloPlayerListener(EventNode node) { + EventBus.getBus().register(this); + + node.addListener(PlayerPluginMessageEvent.class, this::onPlayerPluginMessage); + node.addListener(PlayerDisconnectEvent.class, this::onPlayerDisconnect); + node.addListener(PlayerSpawnEvent.class, this::onPlayerSpawn); + } + + private void onPlayerPluginMessage(PlayerPluginMessageEvent event) { + Player player = event.getPlayer(); + String identifier = event.getIdentifier(); + + switch (identifier) { + case "minecraft:register": { + if (this.getChannels(event.getMessageString()).contains(ApolloManager.PLUGIN_MESSAGE_CHANNEL)) { + ((ApolloPlayerManagerImpl) Apollo.getPlayerManager()).addPlayer(new MinestomApolloPlayer(player)); + } + + break; + } + + case "minecraft:unregister": { + if (this.getChannels(event.getMessageString()).contains(ApolloManager.PLUGIN_MESSAGE_CHANNEL)) { + ((ApolloPlayerManagerImpl) Apollo.getPlayerManager()).removePlayer(player.getUuid()); + } + + break; + } + + case ApolloManager.PLUGIN_MESSAGE_CHANNEL: { + ApolloManager.getNetworkManager().receivePacket(player.getUuid(), event.getMessage()); + break; + } + } + } + + private void onPlayerDisconnect(PlayerDisconnectEvent event) { + ((ApolloPlayerManagerImpl) Apollo.getPlayerManager()).removePlayer(event.getPlayer().getUuid()); + } + + private void onPlayerSpawn(PlayerSpawnEvent event) { + Player player = event.getPlayer(); + + this.sendRegisterPacket(player); + this.sendUpdateMessage(player); + } + + private void sendRegisterPacket(Player player) { + if (ApolloMinestomPlatform.getInstance().getProperties().isSendRegisterPacket()) { + player.sendPluginMessage("minecraft:register", ApolloManager.PLUGIN_MESSAGE_CHANNEL); + } + } + + private void sendUpdateMessage(Player player) { + VersionResponse updateAssets = ApolloManager.getVersionManager().getUpdateAssets(); + if (updateAssets == null) { + return; + } + + if (!Apollo.getPlatform().getOptions().get(ApolloVersionManager.SEND_UPDATE_MESSAGE)) { + return; + } + + String version = updateAssets.getVersion(); + if (version != null && player.getPermissionLevel() == 4) { + Component message = Component.text("[Apollo] A new version of Apollo is available! Latest release: ", NamedTextColor.YELLOW) + .append(Component.text(version, NamedTextColor.GOLD)); + + player.sendMessage(message); + } + } + + @Listen + private void onApolloReceivePacket(ApolloReceivePacketEvent event) { + event.unpack(PlayerHandshakeMessage.class).ifPresent(message -> { + ((ApolloPlayerManagerImpl) Apollo.getPlayerManager()).handlePlayerHandshake(event.getPlayer(), message); + }); + } + + private List getChannels(String channelsString) { + return Arrays.asList(channelsString.split("\0")); + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloWorldListener.java b/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloWorldListener.java new file mode 100644 index 00000000..8bb625d0 --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/listener/ApolloWorldListener.java @@ -0,0 +1,104 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.listener; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.event.ApolloListener; +import com.lunarclient.apollo.event.EventBus; +import com.lunarclient.apollo.event.Listen; +import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent; +import com.lunarclient.apollo.player.AbstractApolloPlayer; +import com.lunarclient.apollo.player.ApolloPlayer; +import com.lunarclient.apollo.player.v1.UpdatePlayerWorldMessage; +import com.lunarclient.apollo.world.ApolloWorldManagerImpl; +import com.lunarclient.apollo.wrapper.MinestomApolloWorld; +import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.Player; +import net.minestom.server.event.Event; +import net.minestom.server.event.EventNode; +import net.minestom.server.event.instance.InstanceRegisterEvent; +import net.minestom.server.event.instance.InstanceUnregisterEvent; +import net.minestom.server.event.player.PlayerSpawnEvent; +import net.minestom.server.instance.Instance; + +/** + * Handles registration and un-registration of Apollo worlds. + * + * @since 1.2.0 + */ +public final class ApolloWorldListener implements ApolloListener { + + /** + * Constructs the {@link ApolloWorldListener}. + * + * @param node the node + * @since 1.2.0 + */ + public ApolloWorldListener(EventNode node) { + EventBus.getBus().register(this); + + ApolloWorldManagerImpl worldManager = ((ApolloWorldManagerImpl) Apollo.getWorldManager()); + for (Instance world : MinecraftServer.getInstanceManager().getInstances()) { + worldManager.addWorld(new MinestomApolloWorld(world)); + } + + node.addListener(InstanceRegisterEvent.class, this::onInstanceRegister); + node.addListener(InstanceUnregisterEvent.class, this::onInstanceUnregister); + node.addListener(PlayerSpawnEvent.class, this::onPlayerSpawn); + } + + private void onInstanceRegister(InstanceRegisterEvent event) { + ((ApolloWorldManagerImpl) Apollo.getWorldManager()).addWorld(new MinestomApolloWorld(event.getInstance())); + } + + private void onInstanceUnregister(InstanceUnregisterEvent event) { + ((ApolloWorldManagerImpl) Apollo.getWorldManager()).removeWorld(event.getInstance().getUuid().toString()); + } + + private void onPlayerSpawn(PlayerSpawnEvent event) { + Player player = event.getPlayer(); + + Apollo.getPlayerManager().getPlayer(player.getUuid()).ifPresent(apolloPlayer -> { + UpdatePlayerWorldMessage message = UpdatePlayerWorldMessage.newBuilder() + .setWorld(player.getInstance().getUuid().toString()) + .build(); + + ((AbstractApolloPlayer) apolloPlayer).sendPacket(message); + }); + } + + @Listen + private void onApolloRegisterPlayer(ApolloRegisterPlayerEvent event) { + ApolloPlayer apolloPlayer = event.getPlayer(); + + apolloPlayer.getWorld().ifPresent(world -> { + UpdatePlayerWorldMessage message = UpdatePlayerWorldMessage.newBuilder() + .setWorld(world.getName()) + .build(); + + ((AbstractApolloPlayer) apolloPlayer).sendPacket(message); + }); + } + +} diff --git a/folia/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java b/minestom/src/main/java/com/lunarclient/apollo/metadata/MinestomMetadata.java similarity index 51% rename from folia/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java rename to minestom/src/main/java/com/lunarclient/apollo/metadata/MinestomMetadata.java index a4b8bfce..160bc33a 100644 --- a/folia/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java +++ b/minestom/src/main/java/com/lunarclient/apollo/metadata/MinestomMetadata.java @@ -21,45 +21,40 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.lunarclient.apollo.command.impl; +package com.lunarclient.apollo.metadata; -import com.lunarclient.apollo.ApolloManager; -import com.lunarclient.apollo.command.FoliaApolloCommand; -import com.lunarclient.apollo.common.ApolloComponent; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import com.lunarclient.apollo.stats.metadata.PlatformMetadata; +import java.util.Map; +import java.util.Set; +import lombok.Builder; +import lombok.ToString; /** - * The general Apollo command. + * Represents the minestom metadata implementation. * - * @since 1.1.8 + * @since 1.2.0 */ -public final class ApolloCommand extends FoliaApolloCommand implements CommandExecutor { +@ToString +@Builder(toBuilder = true) +public class MinestomMetadata extends PlatformMetadata { /** - * Returns a new instance of this command. + * Tracks client brands sent by the players. * - * @since 1.1.8 + *

A {@link Set} of {@link String} client brands.

+ * + * @since 1.2.0 */ - public ApolloCommand() { - super((sender, component) -> sender.sendMessage(ApolloComponent.toLegacy(component))); - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if(args.length < 1) { - this.getCurrentVersion(sender); - } else if(args[0].equalsIgnoreCase("reload")) { - this.reloadConfiguration(sender); - } else if(args[0].equalsIgnoreCase("update")) { - ApolloManager.getVersionManager().forceUpdate( - "folia", - message -> this.textConsumer.accept(sender, message) - ); - } + private final Set clientBrands; - return true; - } + /** + * Tracks the total number of resource pack status events received. + * + *

Represents a {@link Map} of {@link String} status enum name as a key + * and {@link Integer} count of how many times that status has been reported.

+ * + * @since 1.2.0 + */ + private final Map resourcePackStatuses; } diff --git a/minestom/src/main/java/com/lunarclient/apollo/metadata/MinestomMetadataManager.java b/minestom/src/main/java/com/lunarclient/apollo/metadata/MinestomMetadataManager.java new file mode 100644 index 00000000..0ba96256 --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/metadata/MinestomMetadataManager.java @@ -0,0 +1,59 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.metadata; + +import com.lunarclient.apollo.stats.metadata.ApolloMetadataManager; +import com.lunarclient.apollo.stats.metadata.PlatformMetadata; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import lombok.Getter; + +/** + * The Minestom implementation of {@link ApolloMetadataManager}. + * + * @since 1.2.0 + */ +@Getter +public class MinestomMetadataManager implements ApolloMetadataManager { + + private final Set clientBrands = new HashSet<>(); + private final Map resourcePackStatuses = new HashMap<>(); + + @Override + public PlatformMetadata extract() { + return MinestomMetadata.builder() + .clientBrands(new HashSet<>(this.clientBrands)) + .resourcePackStatuses(new HashMap<>(this.resourcePackStatuses)) + .build(); + } + + @Override + public void clear() { + this.clientBrands.clear(); + this.resourcePackStatuses.clear(); + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/util/ByteBufUtil.java b/minestom/src/main/java/com/lunarclient/apollo/util/ByteBufUtil.java new file mode 100644 index 00000000..fa4b09ac --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/util/ByteBufUtil.java @@ -0,0 +1,83 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.util; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * Represents a util for reading byte buffs. + * + * @since 1.2.0 + */ +public final class ByteBufUtil { + + /** + * Reads an int from the given input stream. + * + * @param in in the {@link ByteBuffer} to read from + * @return the read int + * @throws IllegalArgumentException if the value length is invalid or too large + * @since 1.2.0 + */ + public static int readVarInt(ByteBuffer in) { + int i = 0; + int j = 0; + + while (true) { + byte b = in.get(); + i |= (b & 0x7F) << j++ * 7; + + if (j > 5) { + throw new RuntimeException("VarInt too big"); + } + + if ((b & 0x80) != 128) { + break; + } + } + + return i; + } + + /** + * Reads a UTF-8 encoded string from the given input stream. + * + * @param in the {@link ByteBuffer} to read from + * @return the decoded string + * @throws IllegalArgumentException if the value length is invalid or too large + * @since 1.2.0 + */ + public static String readString(ByteBuffer in) { + int length = ByteBufUtil.readVarInt(in); + byte[] bytes = new byte[length]; + in.get(bytes); + + return new String(bytes, StandardCharsets.UTF_8); + } + + private ByteBufUtil() { + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloPlayer.java b/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloPlayer.java new file mode 100644 index 00000000..ae2d8e41 --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloPlayer.java @@ -0,0 +1,96 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.wrapper; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.common.location.ApolloLocation; +import com.lunarclient.apollo.player.AbstractApolloPlayer; +import com.lunarclient.apollo.player.ApolloPlayer; +import com.lunarclient.apollo.world.ApolloWorld; +import java.util.Optional; +import java.util.UUID; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.kyori.adventure.audience.Audience; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Player; +import net.minestom.server.instance.Instance; +import org.jetbrains.annotations.NotNull; + +/** + * The Minestom implementation of {@link ApolloPlayer}. + * + * @since 1.2.0 + */ +@Getter +@RequiredArgsConstructor +public final class MinestomApolloPlayer extends AbstractApolloPlayer { + + private final Player player; + + @Override + public UUID getUniqueId() { + return this.player.getUuid(); + } + + @Override + public String getName() { + return this.player.getUsername(); + } + + @Override + public Optional getWorld() { + Instance instance = this.player.getInstance(); + + return Apollo.getWorldManager().getWorld(instance.getUuid().toString()); + } + + @Override + public Optional getLocation() { + Pos position = this.player.getPosition(); + + return Optional.of(ApolloLocation.builder() + .world(this.player.getInstance().getUuid().toString()) + .x(position.x()) + .y(position.y()) + .z(position.z()) + .build()); + } + + @Override + public boolean hasPermission(String permissionNode) { + throw new UnsupportedOperationException("Permission checks are not supported in Minestom."); + } + + @Override + public void sendPacket(byte[] messages) { + this.player.sendPluginMessage(ApolloManager.PLUGIN_MESSAGE_CHANNEL, messages); + } + + @Override + public @NotNull Audience audience() { + return this.player; + } +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloStats.java b/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloStats.java new file mode 100644 index 00000000..c447123f --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloStats.java @@ -0,0 +1,104 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.wrapper; + +import com.lunarclient.apollo.ApolloMinestomPlatform; +import com.lunarclient.apollo.stats.ApolloPluginDescription; +import com.lunarclient.apollo.stats.ApolloStats; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import javax.imageio.ImageIO; +import net.minestom.server.Auth; +import net.minestom.server.Git; +import net.minestom.server.MinecraftServer; + +/** + * The Minestom implementation of {@link ApolloStats}. + * + * @since 1.2.0 + */ +public class MinestomApolloStats implements ApolloStats { + + @Override + public boolean isOnlineMode() { + return MinecraftServer.process().auth() instanceof Auth.Online; + } + + @Override + public String getIcon() { + try (InputStream stream = ApolloMinestomPlatform.class.getResourceAsStream("/favicon.png")) { + if (stream == null) { + return null; + } + + BufferedImage image = ImageIO.read(stream); + if (image == null) { + return null; + } + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + ImageIO.write(image, "PNG", outputStream); + } catch (IOException e) { + return null; + } + + byte[] bytes = outputStream.toByteArray(); + return Base64.getEncoder().encodeToString(bytes); + } catch (Exception e) { + return null; + } + } + + @Override + public String getVersion() { + return MinecraftServer.VERSION_NAME; + } + + @Override + public List getPlugins() { + return Collections.emptyList(); + } + + @Override + public String getPlatformSubtype() { + return "Minestom"; + } + + @Override + public String getPlatformVersion() { + return Git.version(); + } + + @Override + public int getTotalPlayers() { + return MinecraftServer.getConnectionManager().getOnlinePlayerCount(); + } + +} diff --git a/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloWorld.java b/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloWorld.java new file mode 100644 index 00000000..ed53112d --- /dev/null +++ b/minestom/src/main/java/com/lunarclient/apollo/wrapper/MinestomApolloWorld.java @@ -0,0 +1,66 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2023 Moonsworth + * + * 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. + */ +package com.lunarclient.apollo.wrapper; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.player.ApolloPlayer; +import com.lunarclient.apollo.recipients.ForwardingRecipients; +import com.lunarclient.apollo.recipients.Recipients; +import com.lunarclient.apollo.world.ApolloWorld; +import java.util.Collection; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import net.minestom.server.instance.Instance; + +/** + * The Minestom implementation of {@link ApolloWorld}. + * + * @since 1.2.0 + */ +@AllArgsConstructor +public final class MinestomApolloWorld implements ApolloWorld, ForwardingRecipients { + + private final Instance instance; + + @Override + public String getName() { + return this.instance.getUuid().toString(); + } + + @Override + public Collection getPlayers() { + return this.instance.getPlayers().stream() + .map(player -> Apollo.getPlayerManager().getPlayer(player.getUuid())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } + + @Override + public Iterable recipients() { + return this.getPlayers(); + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 3c0b977e..359d9aa4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -40,9 +40,11 @@ listOfNotNull( "example:bukkit:api", "example:bukkit:json", "example:bukkit:proto", + "example:minestom:api", if (loadAllVersions) "bungee" else null, if (loadAllVersions) "velocity" else null, - if (loadAllVersions) "folia" else null + if (loadAllVersions) "folia" else null, + if (loadAllVersions) "minestom" else null ).forEach { include(it) findProject(":$it")?.name = "apollo-${it.replace(':', '-')}" diff --git a/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java b/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java index 830221e1..dcfcb598 100644 --- a/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java +++ b/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java @@ -24,8 +24,8 @@ package com.lunarclient.apollo; import com.google.inject.Inject; -import com.lunarclient.apollo.command.impl.ApolloCommand; -import com.lunarclient.apollo.command.impl.LunarClientCommand; +import com.lunarclient.apollo.command.VelocityApolloCommand; +import com.lunarclient.apollo.command.VelocityLunarClientCommand; import com.lunarclient.apollo.listener.ApolloMetadataListener; import com.lunarclient.apollo.listener.ApolloPlayerListener; import com.lunarclient.apollo.metadata.VelocityMetadataManager; @@ -134,6 +134,11 @@ public Kind getKind() { return Kind.PROXY; } + @Override + public Platform getPlatform() { + return Platform.VELOCITY; + } + @Override public String getApolloVersion() { return this.server.getPluginManager().fromInstance(this) @@ -214,8 +219,8 @@ public void onProxyInitialization(ProxyInitializeEvent event) { channelRegistrar.register(ApolloMetadataListener.FML_HANDSHAKE_CHANNEL); CommandManager commandManager = this.server.getCommandManager(); - commandManager.register(ApolloCommand.create()); - commandManager.register(LunarClientCommand.create()); + commandManager.register(VelocityApolloCommand.create()); + commandManager.register(VelocityLunarClientCommand.create()); ApolloManager.getStatsManager().enable(); ApolloManager.getVersionManager().checkForUpdates(); diff --git a/velocity/src/main/java/com/lunarclient/apollo/command/VelocityApolloCommand.java b/velocity/src/main/java/com/lunarclient/apollo/command/VelocityApolloCommand.java index 14f01273..b482a150 100644 --- a/velocity/src/main/java/com/lunarclient/apollo/command/VelocityApolloCommand.java +++ b/velocity/src/main/java/com/lunarclient/apollo/command/VelocityApolloCommand.java @@ -23,52 +23,71 @@ */ package com.lunarclient.apollo.command; -import com.lunarclient.apollo.ApolloVelocityPlatform; -import com.velocitypowered.api.proxy.Player; -import java.util.Optional; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import lombok.NonNull; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.ApolloPlatform; +import com.lunarclient.apollo.command.type.ApolloCommand; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.velocitypowered.api.command.BrigadierCommand; +import com.velocitypowered.api.command.CommandSource; +import lombok.Getter; +import net.kyori.adventure.audience.Audience; /** - * Provides common command functions for Velocity. + * The general Apollo command. * - * @param the sender type - * @since 1.0.9 + * @since 1.0.5 */ -public abstract class VelocityApolloCommand extends AbstractApolloCommand { +@Getter +public final class VelocityApolloCommand extends ApolloCommand { /** - * Returns a new instance of a Velocity command. + * Returns a new instance of this command. * - * @param textConsumer the consumer for sending messages to the sender - * @since 1.0.9 + * @return a new command + * @since 1.0.5 */ - public VelocityApolloCommand(BiConsumer textConsumer) { - super(textConsumer); + public static BrigadierCommand create() { + VelocityApolloCommand command = new VelocityApolloCommand(); + + return new BrigadierCommand(LiteralArgumentBuilder.literal("apollo") + .requires(source -> source.hasPermission("apollo.command")) + .executes(command.getBaseCommand()) + .then(LiteralArgumentBuilder.literal("reload") + .executes(command.getReloadCommand()) + .build() + ) + .then(LiteralArgumentBuilder.literal("update") + .executes(command.getUpdateCommand()) + .build() + ) + .build() + ); } - /** - * Handles a player argument; if the provided player doesn't exist, a not found message - * is sent to the sender. Otherwise, the player is passed to the provided player consumer. - * - * @param sender the command sender - * @param argument the argument passed from the command execution - * @param playerConsumer a consumer used for processing a desired action if the player is found - * @since 1.0.9 - */ - protected void handlePlayerArgument(@NonNull T sender, @NonNull String argument, @NonNull Consumer playerConsumer) { - Optional playerOpt = ApolloVelocityPlatform.getInstance().getServer().getPlayer(argument); + private final Command baseCommand = context -> { + CommandSource source = context.getSource(); + this.getCurrentVersion(source); + return Command.SINGLE_SUCCESS; + }; - if (!playerOpt.isPresent()) { - this.textConsumer.accept(sender, Component.text("Player '", NamedTextColor.RED) - .append(Component.text(argument, NamedTextColor.RED)) - .append(Component.text("' not found!", NamedTextColor.RED))); - return; - } + private final Command reloadCommand = context -> { + CommandSource source = context.getSource(); + this.reloadConfiguration(source); + return Command.SINGLE_SUCCESS; + }; - playerConsumer.accept(playerOpt.get()); + private final Command updateCommand = context -> { + ApolloManager.getVersionManager().forceUpdate( + ApolloPlatform.Platform.VELOCITY, + message -> this.textConsumer.accept(context.getSource(), message) + ); + + return Command.SINGLE_SUCCESS; + }; + + VelocityApolloCommand() { + super(Audience::sendMessage); } + } diff --git a/velocity/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java b/velocity/src/main/java/com/lunarclient/apollo/command/VelocityLunarClientCommand.java similarity index 64% rename from velocity/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java rename to velocity/src/main/java/com/lunarclient/apollo/command/VelocityLunarClientCommand.java index d7b1e84f..6013ebf3 100644 --- a/velocity/src/main/java/com/lunarclient/apollo/command/impl/LunarClientCommand.java +++ b/velocity/src/main/java/com/lunarclient/apollo/command/VelocityLunarClientCommand.java @@ -21,16 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.lunarclient.apollo.command.impl; +package com.lunarclient.apollo.command; import com.lunarclient.apollo.Apollo; -import com.lunarclient.apollo.command.VelocityApolloCommand; +import com.lunarclient.apollo.ApolloVelocityPlatform; +import com.lunarclient.apollo.command.type.LunarClientCommand; import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.velocitypowered.api.command.BrigadierCommand; import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.proxy.Player; +import java.util.Optional; import lombok.Getter; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; @@ -42,7 +45,7 @@ * @since 1.0.9 */ @Getter -public final class LunarClientCommand extends VelocityApolloCommand { +public final class VelocityLunarClientCommand extends LunarClientCommand { /** * Returns a new instance of this command. @@ -51,7 +54,7 @@ public final class LunarClientCommand extends VelocityApolloCommandliteral("lunarclient") .executes(source -> { @@ -71,25 +74,34 @@ public static BrigadierCommand create() { String argument = context.getArgument("player", String.class); CommandSource source = context.getSource(); - this.handlePlayerArgument(source, argument, player -> { - Component message = Component.text("Player ", NamedTextColor.GRAY) - .append(Component.text(player.getUsername(), NamedTextColor.AQUA)) - .append(Component.text(" is ", NamedTextColor.GRAY)); + Optional playerOpt = ApolloVelocityPlatform.getInstance().getServer().getPlayer(argument); - if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { - message = message.append(Component.text("using ", NamedTextColor.GREEN)); - } else { - message = message.append(Component.text("not using ", NamedTextColor.RED)); - } + if (!playerOpt.isPresent()) { + this.textConsumer.accept(source, Component.text("Player '", NamedTextColor.RED) + .append(Component.text(argument, NamedTextColor.RED)) + .append(Component.text("' not found!", NamedTextColor.RED))); + return Command.SINGLE_SUCCESS; + } - message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); - this.textConsumer.accept(source, message); - }); + Player player = playerOpt.get(); + + Component message = Component.text("Player ", NamedTextColor.GRAY) + .append(Component.text(player.getUsername(), NamedTextColor.AQUA)) + .append(Component.text(" is ", NamedTextColor.GRAY)); + + if (Apollo.getPlayerManager().hasSupport(player.getUniqueId())) { + message = message.append(Component.text("using ", NamedTextColor.GREEN)); + } else { + message = message.append(Component.text("not using ", NamedTextColor.RED)); + } + + message = message.append(Component.text("Lunar Client!", NamedTextColor.GRAY)); + this.textConsumer.accept(source, message); return Command.SINGLE_SUCCESS; }; - LunarClientCommand() { + VelocityLunarClientCommand() { super(Audience::sendMessage); this.setUsage("/lunarclient "); diff --git a/velocity/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java b/velocity/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java deleted file mode 100644 index efb797a0..00000000 --- a/velocity/src/main/java/com/lunarclient/apollo/command/impl/ApolloCommand.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of Apollo, licensed under the MIT License. - * - * Copyright (c) 2023 Moonsworth - * - * 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. - */ -package com.lunarclient.apollo.command.impl; - -import com.lunarclient.apollo.ApolloManager; -import com.lunarclient.apollo.command.VelocityApolloCommand; -import com.mojang.brigadier.Command; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.velocitypowered.api.command.BrigadierCommand; -import com.velocitypowered.api.command.CommandSource; -import lombok.Getter; -import net.kyori.adventure.audience.Audience; - -/** - * The general Apollo command. - * - * @since 1.0.5 - */ -@Getter -public final class ApolloCommand extends VelocityApolloCommand { - - /** - * Returns a new instance of this command. - * - * @return a new command - * @since 1.0.5 - */ - public static BrigadierCommand create() { - ApolloCommand command = new ApolloCommand(); - - return new BrigadierCommand(LiteralArgumentBuilder.literal("apollo") - .requires(source -> source.hasPermission("apollo.command")) - .executes(command.getBaseCommand()) - .then(LiteralArgumentBuilder.literal("reload") - .executes(command.getReloadCommand()) - .build() - ) - .then(LiteralArgumentBuilder.literal("update") - .executes(command.getUpdateCommand()) - .build() - ) - .build() - ); - } - - private final Command baseCommand = context -> { - CommandSource source = context.getSource(); - ApolloCommand.this.getCurrentVersion(source); - return Command.SINGLE_SUCCESS; - }; - - private final Command reloadCommand = context -> { - CommandSource source = context.getSource(); - this.reloadConfiguration(source); - return Command.SINGLE_SUCCESS; - }; - - private final Command updateCommand = context -> { - ApolloManager.getVersionManager().forceUpdate( - "velocity", - message -> this.textConsumer.accept(context.getSource(), message) - ); - - return Command.SINGLE_SUCCESS; - }; - - ApolloCommand() { - super(Audience::sendMessage); - } - -}