diff --git a/README.md b/README.md index 685ad4ff..01f0f66b 100644 --- a/README.md +++ b/README.md @@ -24,5 +24,6 @@ - cloud-sponge7: integration for [Sponge API](https://spongepowered.org) v7 - cloud-bungee: integration for Bungeecord API - cloud-cloudburst: integration for cloudburst +- cloud-waterdog: integration for [WaterdogPE](https://waterdog.dev) API - cloud-minecraft-extras: optional extras using [adventure](https://github.com/KyoriPowered/adventure) API - cloud-minecraft-bom: [bill of materials](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Importing_Dependencies) for cloud-minecraft dependencies diff --git a/cloud-waterdog/build.gradle.kts b/cloud-waterdog/build.gradle.kts new file mode 100644 index 00000000..f9e5e289 --- /dev/null +++ b/cloud-waterdog/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("conventions.base") + id("conventions.publishing") +} + +dependencies { + api(libs.cloud.core) + compileOnly(libs.waterdog) { + isTransitive = false + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCaptionKeys.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCaptionKeys.java new file mode 100644 index 00000000..e12dad42 --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCaptionKeys.java @@ -0,0 +1,68 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.caption.Caption; + +/** + * WaterdogPE specific {@link Caption caption keys} + * + * @since 2.0.0 + */ +public final class WaterdogCaptionKeys { + + private static final Collection RECOGNIZED_CAPTIONS = new LinkedList<>(); + + /** + * Variables: {@code } + */ + public static final Caption ARGUMENT_PARSE_FAILURE_PLAYER = of("argument.parse.failure.player"); + + /** + * Variables: {@code } + */ + public static final Caption ARGUMENT_PARSE_FAILURE_SERVER = of("argument.parse.failure.server"); + + private WaterdogCaptionKeys() { + } + + private static @NonNull Caption of(final @NonNull String key) { + final Caption caption = Caption.of(key); + RECOGNIZED_CAPTIONS.add(caption); + return caption; + } + + /** + * Returns an immutable collection containing all standard caption keys. + * + * @return immutable collection of keys + */ + public static @NonNull Collection<@NonNull Caption> waterdogCaptionKeys() { + return Collections.unmodifiableCollection(RECOGNIZED_CAPTIONS); + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommand.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommand.java new file mode 100644 index 00000000..794a8e34 --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommand.java @@ -0,0 +1,66 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog; + +import dev.waterdog.waterdogpe.command.Command; +import dev.waterdog.waterdogpe.command.CommandSender; +import dev.waterdog.waterdogpe.command.CommandSettings; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.incendo.cloud.component.CommandComponent; + +final class WaterdogCommand extends Command { + + private final WaterdogCommandManager manager; + private final CommandComponent command; + + WaterdogCommand( + final org.incendo.cloud.@NonNull Command cloudCommand, + final @NonNull CommandComponent command, + final @NonNull WaterdogCommandManager manager + ) { + super( + command.name(), + CommandSettings.builder() + .setAliases(command.alternativeAliases().toArray(new String[0])) + .setDescription(cloudCommand.commandDescription().description().textDescription()) + .setPermission(cloudCommand.commandPermission().toString()) + .build() + ); + this.command = command; + this.manager = manager; + } + + @Override + public boolean onExecute(final CommandSender sender, final @Nullable String alias, final String[] args) { + /* Join input */ + final StringBuilder builder = new StringBuilder(this.command.name()); + for (final String arg : args) { + builder.append(" ").append(arg); + } + final C cloudSender = this.manager.senderMapper().map(sender); + this.manager.commandExecutor().executeCommand(cloudSender, builder.toString()); + return true; + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommandManager.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommandManager.java new file mode 100644 index 00000000..46c96360 --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommandManager.java @@ -0,0 +1,134 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog; + +import dev.waterdog.waterdogpe.command.CommandSender; +import dev.waterdog.waterdogpe.plugin.Plugin; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.SenderMapper; +import org.incendo.cloud.SenderMapperHolder; +import org.incendo.cloud.caption.CaptionProvider; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.waterdog.parser.PlayerParser; +import org.incendo.cloud.waterdog.parser.ServerParser; + +/** + * Command manager for the WaterdogPE platform + * + * @param Command sender type + * @since 2.0.0 + */ +public class WaterdogCommandManager extends CommandManager implements SenderMapperHolder { + + /** + * Default caption for {@link WaterdogCaptionKeys#ARGUMENT_PARSE_FAILURE_PLAYER} + */ + public static final String ARGUMENT_PARSE_FAILURE_PLAYER = "'' is not a valid player"; + + /** + * Default caption for {@link WaterdogCaptionKeys#ARGUMENT_PARSE_FAILURE_SERVER} + */ + public static final String ARGUMENT_PARSE_FAILURE_SERVER = "'' is not a valid server"; + + /** + * WaterdogPE color code used to highlight error messages sent to command senders. + */ + private static final String RED_COLOR_CODE = "§c"; + + private final Plugin owningPlugin; + private final SenderMapper senderMapper; + + /** + * Construct a new WaterdogPE command manager + * + * @param owningPlugin Plugin that is constructing the manager + * @param commandExecutionCoordinator Coordinator provider + * @param senderMapper Function that maps {@link CommandSender} to the command sender type + */ + @SuppressWarnings("this-escape") + public WaterdogCommandManager( + final @NonNull Plugin owningPlugin, + final @NonNull ExecutionCoordinator commandExecutionCoordinator, + final @NonNull SenderMapper senderMapper + ) { + super(commandExecutionCoordinator, new WaterdogPluginRegistrationHandler<>()); + ((WaterdogPluginRegistrationHandler) this.commandRegistrationHandler()).initialize(this); + this.owningPlugin = owningPlugin; + this.senderMapper = senderMapper; + + /* Register WaterdogPE Preprocessor */ + this.registerCommandPreProcessor(new WaterdogCommandPreprocessor<>(this)); + + /* Register WaterdogPE Parsers */ + this.parserRegistry() + .registerParser(PlayerParser.playerParser()) + .registerParser(ServerParser.serverParser()); + + /* Register default captions */ + this.captionRegistry() + .registerProvider(CaptionProvider.constantProvider() + .putCaption(WaterdogCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER, ARGUMENT_PARSE_FAILURE_PLAYER) + .putCaption(WaterdogCaptionKeys.ARGUMENT_PARSE_FAILURE_SERVER, ARGUMENT_PARSE_FAILURE_SERVER) + .build()); + + this.registerDefaultExceptionHandlers(); + } + + @Override + public final boolean hasPermission( + final @NonNull C sender, + final @NonNull String permission + ) { + if (permission.isEmpty()) { + return true; + } + return this.senderMapper.reverse(sender).hasPermission(permission); + } + + /** + * Returns the owning plugin. + * + * @return owning plugin + */ + public @NonNull Plugin owningPlugin() { + return this.owningPlugin; + } + + private void registerDefaultExceptionHandlers() { + this.registerDefaultExceptionHandlers( + triplet -> { + final CommandSender commandSender = this.senderMapper.reverse(triplet.first().sender()); + final String message = triplet.first().formatCaption(triplet.second(), triplet.third()); + commandSender.sendMessage(RED_COLOR_CODE + message); + }, + pair -> this.owningPlugin.getLogger().error(pair.first(), pair.second()) + ); + } + + @Override + public final @NonNull SenderMapper senderMapper() { + return this.senderMapper; + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommandPreprocessor.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommandPreprocessor.java new file mode 100644 index 00000000..ba833fdf --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogCommandPreprocessor.java @@ -0,0 +1,54 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.execution.preprocessor.CommandPreprocessingContext; +import org.incendo.cloud.execution.preprocessor.CommandPreprocessor; + +/** + * Command preprocessor which decorates incoming {@link org.incendo.cloud.context.CommandContext} + * with WaterdogPE specific objects + * + * @param Command sender type + * @since 2.0.0 + */ +final class WaterdogCommandPreprocessor implements CommandPreprocessor { + + private final WaterdogCommandManager mgr; + + /** + * The WaterdogPE Command Preprocessor for storing WaterdogPE-specific contexts in the command contexts + * + * @param mgr The WaterdogCommandManager + */ + WaterdogCommandPreprocessor(final @NonNull WaterdogCommandManager mgr) { + this.mgr = mgr; + } + + @Override + public void accept(final @NonNull CommandPreprocessingContext context) { + context.commandContext().store(WaterdogContextKeys.PROXY_SERVER_KEY, this.mgr.owningPlugin().getProxy()); + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogContextKeys.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogContextKeys.java new file mode 100644 index 00000000..3c1b83dd --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogContextKeys.java @@ -0,0 +1,48 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog; + +import dev.waterdog.waterdogpe.ProxyServer; +import io.leangen.geantyref.TypeToken; +import org.incendo.cloud.key.CloudKey; + +/** + * WaterdogPE related {@link org.incendo.cloud.context.CommandContext} keys + * + * @since 2.0.0 + */ +public final class WaterdogContextKeys { + + /** + * The {@link ProxyServer} instance is stored in the {@link org.incendo.cloud.context.CommandContext} + * in {@link WaterdogCommandPreprocessor} + */ + public static final CloudKey PROXY_SERVER_KEY = CloudKey.of( + "ProxyServer", + TypeToken.get(ProxyServer.class) + ); + + private WaterdogContextKeys() { + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogPluginRegistrationHandler.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogPluginRegistrationHandler.java new file mode 100644 index 00000000..37b45c4b --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/WaterdogPluginRegistrationHandler.java @@ -0,0 +1,65 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog; + +import java.util.HashMap; +import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.component.CommandComponent; +import org.incendo.cloud.internal.CommandRegistrationHandler; + +final class WaterdogPluginRegistrationHandler implements CommandRegistrationHandler { + + private final Map, dev.waterdog.waterdogpe.command.Command> registeredCommands = new HashMap<>(); + + private WaterdogCommandManager waterdogCommandManager; + + WaterdogPluginRegistrationHandler() { + } + + void initialize(final @NonNull WaterdogCommandManager waterdogCommandManager) { + this.waterdogCommandManager = waterdogCommandManager; + } + + @Override + public boolean registerCommand(final @NonNull Command command) { + /* We only care about the root command argument */ + final CommandComponent component = command.rootComponent(); + if (this.registeredCommands.containsKey(component)) { + return false; + } + final WaterdogCommand waterdogCommand = new WaterdogCommand<>( + command, + component, + this.waterdogCommandManager + ); + final boolean registered = this.waterdogCommandManager.owningPlugin().getProxy() + .getCommandMap().registerCommand(waterdogCommand); + if (registered) { + this.registeredCommands.put(component, waterdogCommand); + } + return registered; + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/package-info.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/package-info.java new file mode 100644 index 00000000..9478bd2f --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/package-info.java @@ -0,0 +1,4 @@ +/** + * WaterdogPE implementation of cloud + */ +package org.incendo.cloud.waterdog; diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/PlayerParser.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/PlayerParser.java new file mode 100644 index 00000000..d43849e4 --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/PlayerParser.java @@ -0,0 +1,120 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog.parser; + +import dev.waterdog.waterdogpe.player.ProxiedPlayer; +import java.util.stream.Collectors; +import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.caption.CaptionVariable; +import org.incendo.cloud.component.CommandComponent; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.exception.parsing.ParserException; +import org.incendo.cloud.parser.ArgumentParseResult; +import org.incendo.cloud.parser.ArgumentParser; +import org.incendo.cloud.parser.ParserDescriptor; +import org.incendo.cloud.suggestion.BlockingSuggestionProvider; +import org.incendo.cloud.waterdog.WaterdogCaptionKeys; +import org.incendo.cloud.waterdog.WaterdogContextKeys; + +/** + * Argument parser for {@link ProxiedPlayer players} + * + * @param Command sender type + * @since 2.0.0 + */ +public final class PlayerParser implements ArgumentParser, BlockingSuggestionProvider.Strings { + + /** + * Creates a new player parser. + * + * @param command sender type + * @return the created parser + * @since 2.0.0 + */ + @API(status = API.Status.STABLE, since = "2.0.0") + public static @NonNull ParserDescriptor playerParser() { + return ParserDescriptor.of(new PlayerParser<>(), ProxiedPlayer.class); + } + + /** + * Returns a {@link CommandComponent.Builder} using {@link #playerParser()} as the parser. + * + * @param the command sender type + * @return the component builder + * @since 2.0.0 + */ + @API(status = API.Status.STABLE, since = "2.0.0") + public static CommandComponent.@NonNull Builder playerComponent() { + return CommandComponent.builder().parser(playerParser()); + } + + @Override + public @NonNull ArgumentParseResult<@NonNull ProxiedPlayer> parse( + final @NonNull CommandContext<@NonNull C> commandContext, + final @NonNull CommandInput commandInput + ) { + final String input = commandInput.readString(); + final ProxiedPlayer player = commandContext.get(WaterdogContextKeys.PROXY_SERVER_KEY).getPlayer(input); + if (player == null) { + return ArgumentParseResult.failure( + new PlayerParseException( + input, + commandContext + ) + ); + } + return ArgumentParseResult.success(player); + } + + @Override + public @NonNull Iterable<@NonNull String> stringSuggestions( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return commandContext.get(WaterdogContextKeys.PROXY_SERVER_KEY) + .getPlayers() + .values() + .stream() + .map(ProxiedPlayer::getName) + .collect(Collectors.toList()); + } + + public static final class PlayerParseException extends ParserException { + + + private PlayerParseException( + final @NonNull String input, + final @NonNull CommandContext context + ) { + super( + PlayerParser.class, + context, + WaterdogCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER, + CaptionVariable.of("input", input) + ); + } + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/ServerParser.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/ServerParser.java new file mode 100644 index 00000000..51438612 --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/ServerParser.java @@ -0,0 +1,119 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.cloud.waterdog.parser; + +import dev.waterdog.waterdogpe.network.serverinfo.ServerInfo; +import java.util.stream.Collectors; +import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.caption.CaptionVariable; +import org.incendo.cloud.component.CommandComponent; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.exception.parsing.ParserException; +import org.incendo.cloud.parser.ArgumentParseResult; +import org.incendo.cloud.parser.ArgumentParser; +import org.incendo.cloud.parser.ParserDescriptor; +import org.incendo.cloud.suggestion.BlockingSuggestionProvider; +import org.incendo.cloud.waterdog.WaterdogCaptionKeys; +import org.incendo.cloud.waterdog.WaterdogContextKeys; + +/** + * Argument parser for {@link ServerInfo servers} + * + * @param Command sender type + * @since 2.0.0 + */ +public final class ServerParser implements ArgumentParser, BlockingSuggestionProvider.Strings { + + /** + * Creates a new server parser. + * + * @param command sender type + * @return the created parser + * @since 2.0.0 + */ + @API(status = API.Status.STABLE, since = "2.0.0") + public static @NonNull ParserDescriptor serverParser() { + return ParserDescriptor.of(new ServerParser<>(), ServerInfo.class); + } + + /** + * Returns a {@link CommandComponent.Builder} using {@link #serverParser()} as the parser. + * + * @param the command sender type + * @return the component builder + * @since 2.0.0 + */ + @API(status = API.Status.STABLE, since = "2.0.0") + public static CommandComponent.@NonNull Builder serverComponent() { + return CommandComponent.builder().parser(serverParser()); + } + + @Override + public @NonNull ArgumentParseResult<@NonNull ServerInfo> parse( + final @NonNull CommandContext<@NonNull C> commandContext, + final @NonNull CommandInput commandInput + ) { + final String input = commandInput.readString(); + final ServerInfo server = commandContext.get(WaterdogContextKeys.PROXY_SERVER_KEY).getServerInfo(input); + if (server == null) { + return ArgumentParseResult.failure( + new ServerParseException( + input, + commandContext + ) + ); + } + return ArgumentParseResult.success(server); + } + + @Override + public @NonNull Iterable<@NonNull String> stringSuggestions( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return commandContext.get(WaterdogContextKeys.PROXY_SERVER_KEY) + .getServers() + .stream() + .map(ServerInfo::getServerName) + .collect(Collectors.toList()); + } + + public static final class ServerParseException extends ParserException { + + + private ServerParseException( + final @NonNull String input, + final @NonNull CommandContext context + ) { + super( + ServerParser.class, + context, + WaterdogCaptionKeys.ARGUMENT_PARSE_FAILURE_SERVER, + CaptionVariable.of("input", input) + ); + } + } +} diff --git a/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/package-info.java b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/package-info.java new file mode 100644 index 00000000..4d50210c --- /dev/null +++ b/cloud-waterdog/src/main/java/org/incendo/cloud/waterdog/parser/package-info.java @@ -0,0 +1,27 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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. +// +/** + * WaterdogPE specific argument types + */ +package org.incendo.cloud.waterdog.parser; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 680c6534..2a69cfbc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ bukkit = "1.13.2-R0.1-SNAPSHOT" commodore = "2.2" bungeecord = "1.20-R0.2" cloudburst = "1.0.0-SNAPSHOT" +waterdog = "2.0.4-SNAPSHOT" adventureApi = "4.15.0" adventurePlatform = "4.4.1" paperApi = "1.20.6-R0.1-SNAPSHOT" @@ -47,6 +48,7 @@ reflectionRemapper = "xyz.jpenilla:reflection-remapper:0.1.3" commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" } bungeecord = { group = "net.md-5", name = "bungeecord-api", version.ref = "bungeecord" } cloudburst = { group = "org.cloudburstmc", name = "cloudburst-server", version.ref = "cloudburst" } +waterdog = { group = "dev.waterdog.waterdogpe", name = "waterdog", version.ref = "waterdog" } adventureApi = { group = "net.kyori", name = "adventure-api", version.ref = "adventureApi" } minimessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "adventureApi" } adventurePlatformBukkit = { group = "net.kyori", name = "adventure-platform-bukkit", version.ref = "adventurePlatform" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 169a2052..698bda79 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -45,6 +45,14 @@ dependencyResolutionManagement { name = "sponge" mavenContent { includeGroup("org.spongepowered") } } + /* The WaterdogPE repository, used for cloud-waterdog */ + maven("https://repo.waterdog.dev/main") { + name = "waterdog" + mavenContent { + snapshotsOnly() + includeGroup("dev.waterdog.waterdogpe") + } + } } } @@ -62,6 +70,7 @@ include("cloud-paper") include("cloud-paper-signed-arguments") include("cloud-sponge7") include("cloud-velocity") +include("cloud-waterdog") include("examples/example-bukkit") findProject(":examples/example-bukkit")?.name = "example-bukkit"