diff --git a/CHANGELOG.md b/CHANGELOG.md index c562237f..8ad3c1d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added ServerArgument to cloud-velocity - Added LockableCommandManager to cloud-core - Added VelocityCommandPreprocessor to cloud-velocity + - Added PlayerArgument to cloud-bungee + - Added ServerArgument to cloud-bungee + - Added ExampleBungeePlugin + - Added CaptionKeys to cloud-bungee ## [1.0.2] - 2020-10-18 diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCaptionKeys.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCaptionKeys.java new file mode 100644 index 00000000..0bee79ee --- /dev/null +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCaptionKeys.java @@ -0,0 +1,68 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// 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 cloud.commandframework.bungee; + +import cloud.commandframework.captions.Caption; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; + +/** + * Bungee specific {@link Caption caption keys} + */ +public final class BungeeCaptionKeys { + + private static final Collection RECOGNIZED_CAPTIONS = new LinkedList<>(); + + /** + * Variables: {input} + */ + public static final Caption ARGUMENT_PARSE_FAILURE_PLAYER = of("argument.parse.failure.player"); + + /** + * Variables: {input} + */ + public static final Caption ARGUMENT_PARSE_FAILURE_SERVER = of("argument.parse.failure.server"); + + private BungeeCaptionKeys() { + } + + private static @NonNull Caption of(final @NonNull String key) { + final Caption caption = Caption.of(key); + RECOGNIZED_CAPTIONS.add(caption); + return caption; + } + + /** + * Get an immutable collection containing all standard caption keys + * + * @return Immutable collection of keys + */ + public static @NonNull Collection<@NonNull Caption> getBungeeCaptionKeys() { + return Collections.unmodifiableCollection(RECOGNIZED_CAPTIONS); + } + +} diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandManager.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandManager.java index a8dd1541..43e21ff1 100644 --- a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandManager.java +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandManager.java @@ -25,9 +25,15 @@ package cloud.commandframework.bungee; import cloud.commandframework.CommandManager; import cloud.commandframework.CommandTree; +import cloud.commandframework.bungee.arguments.PlayerArgument; +import cloud.commandframework.bungee.arguments.ServerArgument; +import cloud.commandframework.captions.FactoryDelegatingCaptionRegistry; import cloud.commandframework.execution.CommandExecutionCoordinator; import cloud.commandframework.meta.SimpleCommandMeta; +import io.leangen.geantyref.TypeToken; import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; @@ -35,6 +41,16 @@ import java.util.function.Function; public class BungeeCommandManager extends CommandManager { + /** + * Default caption for {@link BungeeCaptionKeys#ARGUMENT_PARSE_FAILURE_PLAYER} + */ + public static final String ARGUMENT_PARSE_FAILURE_PLAYER = "'{input}' is not a valid player"; + + /** + * Default caption for {@link BungeeCaptionKeys#ARGUMENT_PARSE_FAILURE_PLAYER} + */ + public static final String ARGUMENT_PARSE_FAILURE_SERVER = "'{input}' is not a valid server"; + private final Plugin owningPlugin; private final Function commandSenderMapper; private final Function backwardsCommandSenderMapper; @@ -46,7 +62,6 @@ public class BungeeCommandManager extends CommandManager { * @param commandExecutionCoordinator Coordinator provider * @param commandSenderMapper Function that maps {@link CommandSender} to the command sender type * @param backwardsCommandSenderMapper Function that maps the command sender type to {@link CommandSender} - * @throws Exception If the construction of the manager fails */ public BungeeCommandManager( final @NonNull Plugin owningPlugin, @@ -54,13 +69,32 @@ public class BungeeCommandManager extends CommandManager { @NonNull CommandExecutionCoordinator> commandExecutionCoordinator, final @NonNull Function<@NonNull CommandSender, @NonNull C> commandSenderMapper, final @NonNull Function<@NonNull C, @NonNull CommandSender> backwardsCommandSenderMapper - ) - throws Exception { + ) { super(commandExecutionCoordinator, new BungeePluginRegistrationHandler<>()); ((BungeePluginRegistrationHandler) this.getCommandRegistrationHandler()).initialize(this); this.owningPlugin = owningPlugin; this.commandSenderMapper = commandSenderMapper; this.backwardsCommandSenderMapper = backwardsCommandSenderMapper; + + /* Register Bungee Parsers */ + this.getParserRegistry().registerParserSupplier(TypeToken.get(ProxiedPlayer.class), parserParameters -> + new PlayerArgument.PlayerParser<>(owningPlugin.getProxy())); + this.getParserRegistry().registerParserSupplier(TypeToken.get(ServerInfo.class), parserParameters -> + new ServerArgument.ServerParser<>(owningPlugin.getProxy())); + + /* Register default captions */ + if (this.getCaptionRegistry() instanceof FactoryDelegatingCaptionRegistry) { + final FactoryDelegatingCaptionRegistry factoryDelegatingCaptionRegistry = (FactoryDelegatingCaptionRegistry) + this.getCaptionRegistry(); + factoryDelegatingCaptionRegistry.registerMessageFactory( + BungeeCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER, + (context, key) -> ARGUMENT_PARSE_FAILURE_PLAYER + ); + factoryDelegatingCaptionRegistry.registerMessageFactory( + BungeeCaptionKeys.ARGUMENT_PARSE_FAILURE_SERVER, + (context, key) -> ARGUMENT_PARSE_FAILURE_SERVER + ); + } } @Override diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/PlayerArgument.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/PlayerArgument.java new file mode 100644 index 00000000..e59dfcbc --- /dev/null +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/PlayerArgument.java @@ -0,0 +1,224 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// 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 cloud.commandframework.bungee.arguments; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.bungee.BungeeCaptionKeys; +import cloud.commandframework.captions.CaptionVariable; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.exceptions.parsing.NoInputProvidedException; +import cloud.commandframework.exceptions.parsing.ParserException; +import io.leangen.geantyref.TypeToken; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +/** + * Argument parser for {@link ProxiedPlayer players} + * + * @param Command sender type + */ +public final class PlayerArgument extends CommandArgument { + + private PlayerArgument( + final @NonNull ProxyServer proxyServer, + final boolean required, + final @NonNull String name, + final @Nullable BiFunction, String, List> suggestionProvider, + final @NonNull Collection<@NonNull BiFunction<@NonNull CommandContext, @NonNull Queue<@NonNull String>, + @NonNull ArgumentParseResult>> argumentPreprocessors + ) { + super( + required, + name, + new PlayerParser<>(proxyServer), + "", + TypeToken.get(ProxiedPlayer.class), + suggestionProvider, + argumentPreprocessors + ); + } + + /** + * Create a new argument builder + * + * @param name Argument name + * @param proxyServer Proxy server instance + * @param Command sender type + * @return Constructed builder + **/ + public static CommandArgument.@NonNull Builder newBuilder( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + return new Builder( + name, + proxyServer + ).withParser( + new PlayerParser<>( + proxyServer + ) + ); + } + + /** + * Create a new required player argument + * + * @param name Argument name + * @param proxyServer Proxy server instance + * @param Command sender type + * @return Created argument + */ + public static CommandArgument of( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + return PlayerArgument.newBuilder(name, proxyServer).asRequired().build(); + } + + /** + * Create a new optional player argument + * + * @param name Argument name + * @param proxyServer Proxy server instance + * @param Command sender type + * @return Created argument + */ + public static CommandArgument optional( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + return PlayerArgument.newBuilder(name, proxyServer).asOptional().build(); + } + + + public static final class Builder extends CommandArgument.Builder { + + private final ProxyServer proxyServer; + + private Builder( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + super(TypeToken.get(ProxiedPlayer.class), name); + this.proxyServer = proxyServer; + } + + @Override + public @NonNull CommandArgument<@NonNull C, @NonNull ProxiedPlayer> build() { + return new PlayerArgument<>( + this.proxyServer, + this.isRequired(), + this.getName(), + this.getSuggestionsProvider(), + new LinkedList<>() + ); + } + + } + + + public static final class PlayerParser implements ArgumentParser { + + private final ProxyServer proxyServer; + + /** + * Create a new player parser + * + * @param proxyServer Proxy server instance + */ + public PlayerParser( + final @NonNull ProxyServer proxyServer + ) { + this.proxyServer = proxyServer; + } + + @Override + public @NonNull ArgumentParseResult<@NonNull ProxiedPlayer> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final Queue<@NonNull String> inputQueue + ) { + final String input = inputQueue.peek(); + if (input == null) { + return ArgumentParseResult.failure(new NoInputProvidedException( + PlayerParser.class, + commandContext + )); + } + final ProxiedPlayer player = this.proxyServer.getPlayer(input); + if (player == null) { + return ArgumentParseResult.failure( + new PlayerParseException( + input, + commandContext + ) + ); + } + inputQueue.remove(); + return ArgumentParseResult.success(player); + } + + @Override + public @NonNull List<@NonNull String> suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + return this.proxyServer.getPlayers().stream().map(ProxiedPlayer::getDisplayName).collect(Collectors.toList()); + } + + @Override + public boolean isContextFree() { + return true; + } + + } + + + public static final class PlayerParseException extends ParserException { + + private PlayerParseException( + final @NonNull String input, + final @NonNull CommandContext context + ) { + super( + PlayerParser.class, + context, + BungeeCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER, + CaptionVariable.of("input", input) + ); + } + + } + +} diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/ServerArgument.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/ServerArgument.java new file mode 100644 index 00000000..c20c4d47 --- /dev/null +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/ServerArgument.java @@ -0,0 +1,216 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// 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 cloud.commandframework.bungee.arguments; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.bungee.BungeeCaptionKeys; +import cloud.commandframework.captions.CaptionVariable; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.exceptions.parsing.NoInputProvidedException; +import cloud.commandframework.exceptions.parsing.ParserException; +import io.leangen.geantyref.TypeToken; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.config.ServerInfo; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.function.BiFunction; + +/** + * Argument parser for {@link net.md_5.bungee.api.config.ServerInfo servers} + * + * @param Command sender type + */ +public final class ServerArgument extends CommandArgument { + + private ServerArgument( + final @NonNull ProxyServer proxyServer, + final boolean required, + final @NonNull String name, + final @Nullable BiFunction, String, List> suggestionsProvider, + final @NonNull Collection<@NonNull BiFunction<@NonNull CommandContext, @NonNull Queue<@NonNull String>, + @NonNull ArgumentParseResult>> argumentPreprocessors + ) { + super( + required, + name, + new ServerParser<>(proxyServer), + "", + TypeToken.get(ServerInfo.class), + suggestionsProvider, + argumentPreprocessors + ); + } + + /** + * Create a new argument builder + * + * @param name Argument name + * @param proxyServer Proxy server instance + * @param Command sender type + * @return Constructed builder + */ + public static CommandArgument.@NonNull Builder newBuilder( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + return new Builder( + name, + proxyServer + ).withParser( + new ServerParser<>( + proxyServer + ) + ); + } + + /** + * Create a new required server argument + * + * @param name Argument name + * @param proxyServer Proxy server instance + * @param Command sender type + * @return Created argument + */ + public static @NonNull CommandArgument of( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + return ServerArgument.newBuilder(name, proxyServer).asRequired().build(); + } + + /** + * Create a new optional server argument + * + * @param name Argument name + * @param proxyServer Proxy server instance + * @param Command sender type + * @return Created argument + */ + public static @NonNull CommandArgument optional( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + return ServerArgument.newBuilder(name, proxyServer).asOptional().build(); + } + + public static final class Builder extends CommandArgument.Builder { + + private final ProxyServer proxyServer; + + private Builder( + final @NonNull String name, + final @NonNull ProxyServer proxyServer + ) { + super(TypeToken.get(ServerInfo.class), name); + this.proxyServer = proxyServer; + } + + @Override + public @NonNull CommandArgument<@NonNull C, @NonNull ServerInfo> build() { + return new ServerArgument<>( + this.proxyServer, + this.isRequired(), + this.getName(), + this.getSuggestionsProvider(), + new LinkedList<>() + ); + } + + } + + public static final class ServerParser implements ArgumentParser { + + private final ProxyServer proxyServer; + + /** + * Create a new server parser + * + * @param proxyServer Proxy server instance + */ + public ServerParser( + final @NonNull ProxyServer proxyServer + ) { + this.proxyServer = proxyServer; + } + + @Override + public @NonNull ArgumentParseResult<@NonNull ServerInfo> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final Queue<@NonNull String> inputQueue + ) { + final String input = inputQueue.peek(); + if (input == null) { + return ArgumentParseResult.failure(new NoInputProvidedException( + ServerParser.class, + commandContext + )); + } + final ServerInfo server = this.proxyServer.getServerInfo(input); + if (server == null) { + return ArgumentParseResult.failure( + new ServerParseException( + input, + commandContext + ) + ); + } + inputQueue.remove(); + return ArgumentParseResult.success(server); + } + + @Override + public @NonNull List<@NonNull String> suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + return new ArrayList<>(this.proxyServer.getServers().keySet()); + } + + } + + public static final class ServerParseException extends ParserException { + + private ServerParseException( + final @NonNull String input, + final @NonNull CommandContext context + ) { + super( + ServerParser.class, + context, + BungeeCaptionKeys.ARGUMENT_PARSE_FAILURE_SERVER, + CaptionVariable.of("input", input) + ); + } + + } + +} diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/package-info.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/package-info.java new file mode 100644 index 00000000..60cc85ce --- /dev/null +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/arguments/package-info.java @@ -0,0 +1,28 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// 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. +// + +/** + * Bungee specific argument types + */ +package cloud.commandframework.bungee.arguments; diff --git a/examples/example-bungee/build.gradle b/examples/example-bungee/build.gradle new file mode 100644 index 00000000..0b7c346d --- /dev/null +++ b/examples/example-bungee/build.gradle @@ -0,0 +1,22 @@ +apply plugin: "com.github.johnrengelman.shadow" + +def adventureVersion = "4.0.0-SNAPSHOT" + +shadowJar { + dependencies { + exclude(dependency("net.md-5:bungeecord-api:1.8-SNAPSHOT")) + } +} + +build.dependsOn(shadowJar) + +dependencies { + /* Cloud */ + implementation project(":cloud-bungee") + implementation project(":cloud-annotations") + implementation project(":cloud-minecraft-extras") + /* Extras */ + implementation "net.kyori:adventure-platform-bungeecord:$adventureVersion" + /* Bungee*/ + compileOnly 'net.md-5:bungeecord-api:1.8-SNAPSHOT' +} diff --git a/examples/example-bungee/src/main/java/cloud/commandframework/examples/bungee/ExamplePlugin.java b/examples/example-bungee/src/main/java/cloud/commandframework/examples/bungee/ExamplePlugin.java new file mode 100644 index 00000000..8c93c41e --- /dev/null +++ b/examples/example-bungee/src/main/java/cloud/commandframework/examples/bungee/ExamplePlugin.java @@ -0,0 +1,150 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// 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 cloud.commandframework.examples.bungee; + +import cloud.commandframework.Command; +import cloud.commandframework.CommandTree; +import cloud.commandframework.Description; +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.bungee.BungeeCommandManager; +import cloud.commandframework.bungee.arguments.PlayerArgument; +import cloud.commandframework.bungee.arguments.ServerArgument; +import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator; +import cloud.commandframework.execution.CommandExecutionCoordinator; +import cloud.commandframework.extra.confirmation.CommandConfirmationManager; +import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler; +import net.kyori.adventure.platform.bungeecord.BungeeAudiences; +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.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Plugin; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public final class ExamplePlugin extends Plugin { + + private BungeeCommandManager manager; + private BungeeAudiences bungeeAudiences; + private CommandConfirmationManager confirmationManager; + + + @Override + public void onEnable() { + final Function, CommandExecutionCoordinator> executionCoordinatorFunction = + AsynchronousCommandExecutionCoordinator.newBuilder().build(); + + final Function mapperFunction = Function.identity(); + + try { + this.manager = new BungeeCommandManager<>( + this, + executionCoordinatorFunction, + mapperFunction, + mapperFunction + ); + } catch (final Exception e) { + this.getLogger().severe("Failed to initialize the command manager"); + return; + } + + this.bungeeAudiences = BungeeAudiences.create(this); + + this.confirmationManager = new CommandConfirmationManager<>( + 30L, + TimeUnit.SECONDS, + context -> bungeeAudiences.sender(context.getCommandContext().getSender()).sendMessage( + Component.text( + "Confirmation required. Confirm using /example confirm.", NamedTextColor.RED)), + sender -> bungeeAudiences.sender(sender).sendMessage( + Component.text("You do not have any pending commands.", NamedTextColor.RED)) + ); + + this.confirmationManager.registerConfirmationProcessor(manager); + + new MinecraftExceptionHandler() + .withInvalidSyntaxHandler() + .withInvalidSenderHandler() + .withNoPermissionHandler() + .withArgumentParsingHandler() + .withDecorator(component -> Component.text() + .append(Component.text("[", NamedTextColor.DARK_GRAY)) + .append(Component.text("Example", NamedTextColor.GOLD)) + .append(Component.text("] ", NamedTextColor.DARK_GRAY)) + .append(component).build() + ).apply(manager, bungeeAudiences::sender); + this.constructCommands(); + } + + private void constructCommands() { + + // Base command builder + // + final Command.Builder builder = this.manager.commandBuilder("example"); + // + // Add a confirmation command + // + this.manager.command(builder.literal("confirm") + .meta("description", "Confirm a pending command") + .handler(this.confirmationManager.createConfirmationExecutionHandler())); + + final CommandArgument playerArgument = PlayerArgument.of("player", this.getProxy()); + final CommandArgument serverArgument = ServerArgument.of("server", this.getProxy()); + + // + // Create a player command + // + this.manager.command( + manager.commandBuilder("player") + .senderType(ProxiedPlayer.class) + .argument(playerArgument, Description.of("Player name")) + .handler(context -> { + final ProxiedPlayer player = context.get("player"); + bungeeAudiences.sender(context.getSender()).sendMessage( + Component.text("Selected ", NamedTextColor.GOLD) + .append(Component.text(player.getDisplayName(), NamedTextColor.AQUA)) + ); + }) + ); + + // + // Create a server command + // + this.manager.command( + this.manager.commandBuilder("server") + .senderType(ProxiedPlayer.class) + .argument(serverArgument, Description.of("Server name")) + .handler(context -> { + final ServerInfo server = context.get("server"); + bungeeAudiences.sender(context.getSender()).sendMessage( + Component.text("Selected ", NamedTextColor.GOLD) + .append(Component.text(server.getName(), NamedTextColor.AQUA)) + ); + }) + ); + } + +} diff --git a/examples/example-bungee/src/main/java/cloud/commandframework/examples/bungee/package-info.java b/examples/example-bungee/src/main/java/cloud/commandframework/examples/bungee/package-info.java new file mode 100644 index 00000000..1e01dd99 --- /dev/null +++ b/examples/example-bungee/src/main/java/cloud/commandframework/examples/bungee/package-info.java @@ -0,0 +1,28 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// 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. +// + +/** + * Bungee example plugin + */ +package cloud.commandframework.examples.bungee; diff --git a/examples/example-bungee/src/main/resources/plugin.yml b/examples/example-bungee/src/main/resources/plugin.yml new file mode 100644 index 00000000..a25e588c --- /dev/null +++ b/examples/example-bungee/src/main/resources/plugin.yml @@ -0,0 +1,5 @@ +name: ExampleBungee +version: "0.2.2" +main: cloud.commandframework.examples.bungee.ExamplePlugin +author: Cloud Contributors +description: "An Example plugin for the Cloud command framework" diff --git a/settings.gradle b/settings.gradle index 78841ac6..41cd99f8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,6 +16,7 @@ include(':example-javacord') include(':cloud-tasks') include(':cloud-sponge') include(':example-velocity') +include(':example-bungee') project(':cloud-bukkit').projectDir = file('cloud-minecraft/cloud-bukkit') project(':cloud-paper').projectDir = file('cloud-minecraft/cloud-paper') project(':cloud-brigadier').projectDir = file('cloud-minecraft/cloud-brigadier') @@ -29,3 +30,5 @@ project(':example-bukkit').projectDir = file('examples/example-bukkit') project(':example-javacord').projectDir = file('examples/example-javacord') project(':cloud-sponge').projectDir = file('cloud-minecraft/cloud-sponge') project(':example-velocity').projectDir = file('examples/example-velocity') +project(':example-bungee').projectDir = file('examples/example-bungee') +