From af6b54b38e50104c86b359d05f81327abf91fd89 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Sun, 21 Jan 2024 10:57:19 -0700 Subject: [PATCH] Make it compile --- ...ingArgumentParser.java => NodeSource.java} | 7 +- .../sponge/SpongeCaptionRegistry.java | 39 +- .../sponge/SpongeCommandManager.java | 188 ++---- .../sponge/SpongeParserMapper.java | 14 +- .../sponge/SpongeRegistrationHandler.java | 7 +- .../sponge/annotation/specifier/Center.java | 6 +- .../sponge/argument/BlockInputArgument.java | 331 ---------- .../argument/BlockPredicateArgument.java | 215 ------ .../sponge/argument/ComponentArgument.java | 181 ----- .../argument/DataContainerArgument.java | 181 ----- .../sponge/argument/GameProfileArgument.java | 198 ------ .../GameProfileCollectionArgument.java | 212 ------ .../argument/ItemStackPredicateArgument.java | 211 ------ .../MultipleEntitySelectorArgument.java | 215 ------ .../MultiplePlayerSelectorArgument.java | 216 ------ .../argument/NamedTextColorArgument.java | 188 ------ .../sponge/argument/OperatorArgument.java | 232 ------- .../argument/ProtoItemStackArgument.java | 346 ---------- .../argument/RegistryEntryArgument.java | 617 ------------------ .../sponge/argument/ResourceKeyArgument.java | 176 ----- .../SingleEntitySelectorArgument.java | 213 ------ .../SinglePlayerSelectorArgument.java | 215 ------ .../sponge/argument/UserArgument.java | 282 -------- .../sponge/argument/Vector2dArgument.java | 250 ------- .../sponge/argument/Vector2iArgument.java | 202 ------ .../sponge/argument/Vector3dArgument.java | 252 ------- .../sponge/argument/Vector3iArgument.java | 200 ------ .../sponge/argument/VectorArgument.java | 110 ---- .../sponge/argument/WorldArgument.java | 216 ------ .../sponge/parser/BlockInputParser.java | 151 +++++ .../sponge/parser/BlockPredicateParser.java | 134 ++++ .../sponge/parser/ComponentParser.java | 80 +++ .../sponge/parser/DataContainerParser.java | 79 +++ .../parser/GameProfileCollectionParser.java | 133 ++++ .../sponge/parser/GameProfileParser.java | 118 ++++ .../parser/ItemStackPredicateParser.java | 130 ++++ .../parser/MultipleEntitySelectorParser.java | 134 ++++ .../parser/MultiplePlayerSelectorParser.java | 135 ++++ .../sponge/parser/NamedTextColorParser.java | 78 +++ .../sponge/parser/OperatorParser.java | 99 +++ .../sponge/parser/ProtoItemStackParser.java | 158 +++++ .../sponge/parser/RegistryEntryParser.java | 258 ++++++++ .../sponge/parser/ResourceKeyParser.java | 66 ++ .../{argument => parser}/ResourceKeyUtil.java | 2 +- .../parser/SingleEntitySelectorParser.java | 131 ++++ .../parser/SinglePlayerSelectorParser.java | 134 ++++ .../sponge/parser/UserParser.java | 207 ++++++ .../sponge/parser/Vector2dParser.java | 104 +++ .../sponge/parser/Vector2iParser.java | 96 +++ .../sponge/parser/Vector3dParser.java | 105 +++ .../sponge/parser/Vector3iParser.java | 94 +++ .../VectorParser.java} | 34 +- .../sponge/parser/WorldParser.java | 112 ++++ .../sponge/parser/package-info.java | 4 + .../examples/sponge/CloudExamplePlugin.java | 577 ++++++++-------- 55 files changed, 3146 insertions(+), 5927 deletions(-) rename cloud-sponge/src/main/java/cloud/commandframework/sponge/{NodeSupplyingArgumentParser.java => NodeSource.java} (87%) delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockInputArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockPredicateArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ComponentArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/DataContainerArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileCollectionArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ItemStackPredicateArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultipleEntitySelectorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultiplePlayerSelectorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/NamedTextColorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/OperatorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ProtoItemStackArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/RegistryEntryArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SingleEntitySelectorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SinglePlayerSelectorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/UserArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2dArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2iArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3dArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3iArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/VectorArgument.java delete mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/WorldArgument.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockInputParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockPredicateParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ComponentParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/DataContainerParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileCollectionParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ItemStackPredicateParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultipleEntitySelectorParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultiplePlayerSelectorParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/NamedTextColorParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/OperatorParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ProtoItemStackParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/RegistryEntryParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyParser.java rename cloud-sponge/src/main/java/cloud/commandframework/sponge/{argument => parser}/ResourceKeyUtil.java (98%) create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SingleEntitySelectorParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SinglePlayerSelectorParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/UserParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2dParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2iParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3dParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3iParser.java rename cloud-sponge/src/main/java/cloud/commandframework/sponge/{argument/package-info.java => parser/VectorParser.java} (52%) create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/WorldParser.java create mode 100644 cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/package-info.java diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/NodeSupplyingArgumentParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/NodeSource.java similarity index 87% rename from cloud-sponge/src/main/java/cloud/commandframework/sponge/NodeSupplyingArgumentParser.java rename to cloud-sponge/src/main/java/cloud/commandframework/sponge/NodeSource.java index b4059958..7fbd3565 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/NodeSupplyingArgumentParser.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/NodeSource.java @@ -28,12 +28,9 @@ import org.spongepowered.api.command.registrar.tree.CommandTreeNode; /** - * An {@link ArgumentParser} which also supplies a special {@link CommandTreeNode.Argument}. - * - * @param sender type - * @param value type + * Implemented by {@link ArgumentParser} which also supply a special {@link CommandTreeNode.Argument}. */ -public interface NodeSupplyingArgumentParser extends ArgumentParser { +public interface NodeSource { /** * Get the node for this parser. diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCaptionRegistry.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCaptionRegistry.java index d6ef55e4..7806f837 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCaptionRegistry.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCaptionRegistry.java @@ -23,6 +23,7 @@ // package cloud.commandframework.sponge; +import cloud.commandframework.captions.CaptionProvider; import cloud.commandframework.captions.StandardCaptionRegistry; /** @@ -36,56 +37,52 @@ public class SpongeCaptionRegistry extends StandardCaptionRegistry { * Default caption for {@link SpongeCaptionKeys#ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY} */ public static final String ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY = - "No such entry '{id}' in registry '{registry}'."; + "No such entry '{id}' in registry '{registry}'."; /** * Default caption for {@link SpongeCaptionKeys#ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME} */ public static final String ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME = - "Cannot find a user with the name '{name}'."; + "Cannot find a user with the name '{name}'."; /** * Default caption for {@link SpongeCaptionKeys#ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID} */ public static final String ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID = - "Cannot find a user with the UUID '{uuid}'."; + "Cannot find a user with the UUID '{uuid}'."; /** * Default caption for {@link SpongeCaptionKeys#ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT} */ public static final String ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT = - "Input '{input}' is not a valid UUID or username."; + "Input '{input}' is not a valid UUID or username."; /** * Default caption for {@link SpongeCaptionKeys#ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED} */ public static final String ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED = - "The provided selector matched multiple game profiles, but only one is allowed."; + "The provided selector matched multiple game profiles, but only one is allowed."; protected SpongeCaptionRegistry() { super(); - this.registerMessageFactory( + this.registerProvider(CaptionProvider.constantProvider() + .putCaptions( SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY, - (caption, sender) -> ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY - ); - this.registerMessageFactory( + ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY) + .putCaptions( SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME, - (caption, sender) -> ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME - ); - this.registerMessageFactory( + ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME) + .putCaptions( SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID, - (caption, sender) -> ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID - ); - this.registerMessageFactory( + ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID) + .putCaptions( SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT, - (caption, sender) -> ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT - ); - this.registerMessageFactory( + ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT) + .putCaptions( SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED, - (caption, sender) -> ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED - ); + ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED) + .build()); } - } diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCommandManager.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCommandManager.java index 20b9fb3c..e45bde68 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCommandManager.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeCommandManager.java @@ -31,36 +31,9 @@ import cloud.commandframework.meta.CommandMeta; import cloud.commandframework.meta.SimpleCommandMeta; import cloud.commandframework.sponge.annotation.specifier.Center; -import cloud.commandframework.sponge.argument.BlockInputArgument; -import cloud.commandframework.sponge.argument.BlockPredicateArgument; -import cloud.commandframework.sponge.argument.ComponentArgument; -import cloud.commandframework.sponge.argument.DataContainerArgument; -import cloud.commandframework.sponge.argument.GameProfileArgument; -import cloud.commandframework.sponge.argument.GameProfileCollectionArgument; -import cloud.commandframework.sponge.argument.ItemStackPredicateArgument; -import cloud.commandframework.sponge.argument.MultipleEntitySelectorArgument; -import cloud.commandframework.sponge.argument.MultiplePlayerSelectorArgument; -import cloud.commandframework.sponge.argument.NamedTextColorArgument; -import cloud.commandframework.sponge.argument.OperatorArgument; -import cloud.commandframework.sponge.argument.ProtoItemStackArgument; -import cloud.commandframework.sponge.argument.RegistryEntryArgument; -import cloud.commandframework.sponge.argument.ResourceKeyArgument; -import cloud.commandframework.sponge.argument.SingleEntitySelectorArgument; -import cloud.commandframework.sponge.argument.SinglePlayerSelectorArgument; -import cloud.commandframework.sponge.argument.UserArgument; -import cloud.commandframework.sponge.argument.Vector2dArgument; -import cloud.commandframework.sponge.argument.Vector2iArgument; -import cloud.commandframework.sponge.argument.Vector3dArgument; -import cloud.commandframework.sponge.argument.Vector3iArgument; -import cloud.commandframework.sponge.argument.WorldArgument; -import cloud.commandframework.sponge.data.BlockPredicate; -import cloud.commandframework.sponge.data.GameProfileCollection; -import cloud.commandframework.sponge.data.ItemStackPredicate; -import cloud.commandframework.sponge.data.MultipleEntitySelector; -import cloud.commandframework.sponge.data.MultiplePlayerSelector; -import cloud.commandframework.sponge.data.ProtoItemStack; -import cloud.commandframework.sponge.data.SingleEntitySelector; -import cloud.commandframework.sponge.data.SinglePlayerSelector; +import cloud.commandframework.sponge.parser.RegistryEntryParser; +import cloud.commandframework.sponge.parser.Vector2dParser; +import cloud.commandframework.sponge.parser.Vector3dParser; import cloud.commandframework.state.RegistrationState; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; @@ -72,27 +45,38 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; -import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandCause; -import org.spongepowered.api.command.parameter.managed.operator.Operator; -import org.spongepowered.api.data.persistence.DataContainer; -import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; -import org.spongepowered.api.profile.GameProfile; import org.spongepowered.api.registry.DefaultedRegistryType; import org.spongepowered.api.registry.Registry; import org.spongepowered.api.registry.RegistryType; import org.spongepowered.api.registry.RegistryTypes; -import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.math.vector.Vector2d; -import org.spongepowered.math.vector.Vector2i; import org.spongepowered.math.vector.Vector3d; -import org.spongepowered.math.vector.Vector3i; import org.spongepowered.plugin.PluginContainer; +import static cloud.commandframework.sponge.parser.BlockInputParser.blockInputParser; +import static cloud.commandframework.sponge.parser.BlockPredicateParser.blockPredicateParser; +import static cloud.commandframework.sponge.parser.ComponentParser.componentParser; +import static cloud.commandframework.sponge.parser.DataContainerParser.dataContainerParser; +import static cloud.commandframework.sponge.parser.GameProfileCollectionParser.gameProfileCollectionParser; +import static cloud.commandframework.sponge.parser.GameProfileParser.gameProfileParser; +import static cloud.commandframework.sponge.parser.ItemStackPredicateParser.itemStackPredicateParser; +import static cloud.commandframework.sponge.parser.MultipleEntitySelectorParser.multipleEntitySelectorParser; +import static cloud.commandframework.sponge.parser.MultiplePlayerSelectorParser.multiplePlayerSelectorParser; +import static cloud.commandframework.sponge.parser.NamedTextColorParser.namedTextColorParser; +import static cloud.commandframework.sponge.parser.OperatorParser.operatorParser; +import static cloud.commandframework.sponge.parser.ProtoItemStackParser.protoItemStackParser; +import static cloud.commandframework.sponge.parser.ResourceKeyParser.resourceKeyParser; +import static cloud.commandframework.sponge.parser.SingleEntitySelectorParser.singleEntitySelectorParser; +import static cloud.commandframework.sponge.parser.SinglePlayerSelectorParser.singlePlayerSelectorParser; +import static cloud.commandframework.sponge.parser.UserParser.userParser; +import static cloud.commandframework.sponge.parser.Vector2iParser.vector2iParser; +import static cloud.commandframework.sponge.parser.Vector3iParser.vector3iParser; +import static cloud.commandframework.sponge.parser.WorldParser.worldParser; + /** * Command manager for Sponge API v8. *

@@ -146,98 +130,38 @@ private void checkLateCreation() { } private void registerParsers() { - this.parserRegistry().registerParserSupplier( - TypeToken.get(ComponentArgument.class), - params -> new ComponentArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(NamedTextColor.class), - params -> new NamedTextColorArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(Operator.class), - params -> new OperatorArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(ServerWorld.class), - params -> new WorldArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(ProtoItemStack.class), - params -> new ProtoItemStackArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(ItemStackPredicate.class), - params -> new ItemStackPredicateArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(ResourceKey.class), - params -> new ResourceKeyArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(GameProfile.class), - params -> new GameProfileArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(GameProfileCollection.class), - params -> new GameProfileCollectionArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(BlockInputArgument.class), - params -> new BlockInputArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(BlockPredicate.class), - params -> new BlockPredicateArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(User.class), - params -> new UserArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(DataContainer.class), - params -> new DataContainerArgument.Parser<>() - ); - - // Position arguments - this.parserRegistry().registerAnnotationMapper( - Center.class, - (annotation, type) -> ParserParameters.single(SpongeParserParameters.CENTER_INTEGERS, true) - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(Vector2d.class), - params -> new Vector2dArgument.Parser<>(params.get(SpongeParserParameters.CENTER_INTEGERS, false)) - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(Vector3d.class), - params -> new Vector3dArgument.Parser<>(params.get(SpongeParserParameters.CENTER_INTEGERS, false)) - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(Vector2i.class), - params -> new Vector2iArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(Vector3i.class), - params -> new Vector3iArgument.Parser<>() - ); - - // Entity selectors - this.parserRegistry().registerParserSupplier( - TypeToken.get(SinglePlayerSelector.class), - params -> new SinglePlayerSelectorArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(MultiplePlayerSelector.class), - params -> new MultiplePlayerSelectorArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(SingleEntitySelector.class), - params -> new SingleEntitySelectorArgument.Parser<>() - ); - this.parserRegistry().registerParserSupplier( - TypeToken.get(MultipleEntitySelector.class), - params -> new MultipleEntitySelectorArgument.Parser<>() - ); + this.parserRegistry() + .registerParser(componentParser()) + .registerParser(namedTextColorParser()) + .registerParser(operatorParser()) + .registerParser(worldParser()) + .registerParser(protoItemStackParser()) + .registerParser(itemStackPredicateParser()) + .registerParser(resourceKeyParser()) + .registerParser(gameProfileParser()) + .registerParser(gameProfileCollectionParser()) + .registerParser(blockInputParser()) + .registerParser(blockPredicateParser()) + .registerParser(userParser()) + .registerParser(dataContainerParser()) + .registerAnnotationMapper( + Center.class, + (annotation, type) -> ParserParameters.single(SpongeParserParameters.CENTER_INTEGERS, true) + ) + .registerParserSupplier( + TypeToken.get(Vector2d.class), + params -> new Vector2dParser<>(params.get(SpongeParserParameters.CENTER_INTEGERS, false)) + ) + .registerParserSupplier( + TypeToken.get(Vector3d.class), + params -> new Vector3dParser<>(params.get(SpongeParserParameters.CENTER_INTEGERS, false)) + ) + .registerParser(vector2iParser()) + .registerParser(vector3iParser()) + .registerParser(singlePlayerSelectorParser()) + .registerParser(multiplePlayerSelectorParser()) + .registerParser(singleEntitySelectorParser()) + .registerParser(multipleEntitySelectorParser()); this.registerRegistryParsers(); } @@ -266,7 +190,7 @@ private void registerRegistryParsers() { this.parserRegistry().registerParserSupplier( TypeToken.get(valueType), - params -> new RegistryEntryArgument.Parser<>(defaultedRegistryType) + params -> new RegistryEntryParser<>(defaultedRegistryType) ); } } diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeParserMapper.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeParserMapper.java index 1383abea..ce6dd582 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeParserMapper.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeParserMapper.java @@ -57,16 +57,6 @@ */ public final class SpongeParserMapper { - private static final Class DELEGATING_SUGGESTIONS_PROVIDER; // todo - ugly - - static { - try { - DELEGATING_SUGGESTIONS_PROVIDER = Class.forName("cloud.commandframework.arguments.DelegatingSuggestionsProvider"); - } catch (final ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - private final Map, Mapping> mappers = new HashMap<>(); SpongeParserMapper() { @@ -100,8 +90,8 @@ CommandTreeNode.Argument> mapParser(final return apply; } result = apply; - } else if (parser instanceof NodeSupplyingArgumentParser) { - result = ((NodeSupplyingArgumentParser) parser).node(); + } else if (parser instanceof NodeSource) { + result = ((NodeSource) parser).node(); } else { result = CommandTreeNodeTypes.STRING.get().createNode().customCompletions().word(); } diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeRegistrationHandler.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeRegistrationHandler.java index 76a8cc8a..658c6c7b 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeRegistrationHandler.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/SpongeRegistrationHandler.java @@ -38,7 +38,7 @@ import static java.util.Objects.requireNonNull; -final class SpongeRegistrationHandler implements CommandRegistrationHandler { +final class SpongeRegistrationHandler implements CommandRegistrationHandler { private SpongeCommandManager commandManager; private final Set> registeredCommands = new HashSet<>(); @@ -74,10 +74,9 @@ void initialize(final @NonNull SpongeCommandManager commandManager) { ); } - @SuppressWarnings("unchecked") @Override - public boolean registerCommand(cloud.commandframework.@NonNull Command command) { - this.registeredCommands.add((cloud.commandframework.Command) command); + public boolean registerCommand(cloud.commandframework.@NonNull Command command) { + this.registeredCommands.add(command); return true; } } diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/annotation/specifier/Center.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/annotation/specifier/Center.java index 01338df3..5254baf7 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/annotation/specifier/Center.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/annotation/specifier/Center.java @@ -23,15 +23,15 @@ // package cloud.commandframework.sponge.annotation.specifier; -import cloud.commandframework.sponge.argument.Vector2dArgument; -import cloud.commandframework.sponge.argument.Vector3dArgument; +import cloud.commandframework.sponge.parser.Vector2dParser; +import cloud.commandframework.sponge.parser.Vector3dParser; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation used to enable coordinate centering for {@link Vector3dArgument} and {@link Vector2dArgument}. + * Annotation used to enable coordinate centering for {@link Vector3dParser} and {@link Vector2dParser}. */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockInputArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockInputArgument.java deleted file mode 100644 index d177fb73..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockInputArgument.java +++ /dev/null @@ -1,331 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.data.BlockInput; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.arguments.blocks.BlockStateArgument; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.block.BlockState; -import org.spongepowered.api.block.BlockType; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.data.persistence.DataContainer; -import org.spongepowered.api.registry.DefaultedRegistryReference; -import org.spongepowered.api.registry.RegistryTypes; -import org.spongepowered.api.world.BlockChangeFlag; -import org.spongepowered.api.world.BlockChangeFlags; -import org.spongepowered.api.world.schematic.PaletteTypes; -import org.spongepowered.api.world.server.ServerLocation; -import org.spongepowered.common.data.persistence.NBTTranslator; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.common.world.SpongeBlockChangeFlag; - -/** - * An argument for parsing {@link BlockInput} from a {@link BlockState} - * and optional extra NBT data. - * - *

Example input strings:

- *
    - *
  • {@code stone}
  • - *
  • {@code minecraft:stone}
  • - *
  • {@code andesite_stairs[waterlogged=true,facing=east]}
  • - *
- * - * @param sender type - */ -public final class BlockInputArgument extends CommandArgument { - - private BlockInputArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - BlockInput.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link BlockInputArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link BlockInputArgument} - */ - public static @NonNull BlockInputArgument of(final @NonNull String name) { - return BlockInputArgument.builder(name).build(); - } - - /** - * Create a new optional {@link BlockInputArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link BlockInputArgument} - */ - public static @NonNull BlockInputArgument optional(final @NonNull String name) { - return BlockInputArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link BlockInputArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link BlockInputArgument} - */ - public static @NonNull BlockInputArgument optional( - final @NonNull String name, - final @NonNull BlockState defaultValue - ) { - return BlockInputArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link BlockInputArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link BlockInputArgument} - */ - public static @NonNull BlockInputArgument optional( - final @NonNull String name, - final @NonNull BlockType defaultValue - ) { - return BlockInputArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link BlockInputArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link BlockInputArgument} - */ - public static @NonNull BlockInputArgument optional( - final @NonNull String name, - final @NonNull DefaultedRegistryReference defaultValue - ) { - return BlockInputArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link BlockState BlockStates}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser(BlockStateArgument.block()) - .map((ctx, blockInput) -> ArgumentParseResult.success(new BlockInputImpl(blockInput))); - - @Override - public @NonNull ArgumentParseResult parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.BLOCK_STATE.get().createNode(); - } - - private static final class BlockInputImpl implements BlockInput { - - // todo: use accessor - private static final Field COMPOUND_TAG_FIELD = - Arrays.stream(net.minecraft.commands.arguments.blocks.BlockInput.class.getDeclaredFields()) - .filter(f -> f.getType().equals(CompoundTag.class)) - .findFirst() - .orElseThrow(IllegalStateException::new); - - static { - COMPOUND_TAG_FIELD.setAccessible(true); - } - - private final net.minecraft.commands.arguments.blocks.BlockInput blockInput; - private final @Nullable DataContainer extraData; - - BlockInputImpl(final net.minecraft.commands.arguments.blocks.@NonNull BlockInput blockInput) { - this.blockInput = blockInput; - try { - final CompoundTag tag = (CompoundTag) COMPOUND_TAG_FIELD.get(blockInput); - this.extraData = tag == null ? null : NBTTranslator.INSTANCE.translate(tag); - } catch (final IllegalAccessException ex) { - throw new RuntimeException(ex); - } - } - - @Override - public @NonNull BlockState blockState() { - return (BlockState) this.blockInput.getState(); - } - - @Override - public @Nullable DataContainer extraData() { - return this.extraData; - } - - @Override - public boolean place(final @NonNull ServerLocation location) { - return this.place(location, BlockChangeFlags.DEFAULT_PLACEMENT); - } - - @Override - public boolean place(final @NonNull ServerLocation location, final @NonNull BlockChangeFlag flag) { - return this.blockInput.place( - (ServerLevel) location.world(), - VecHelper.toBlockPos(location.position()), - ((SpongeBlockChangeFlag) flag).getRawFlag() - ); - } - - } - - } - - /** - * Builder for {@link BlockInputArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(BlockInput.class, name); - } - - @Override - public @NonNull BlockInputArgument build() { - return new BlockInputArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultState default {@link BlockState} - * @param defaultExtraData default extra data - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault( - final @NonNull BlockState defaultState, - final @Nullable DataContainer defaultExtraData - ) { - final String value = PaletteTypes.BLOCK_STATE_PALETTE.get().stringifier() - .apply(RegistryTypes.BLOCK_TYPE.get(), defaultState) - + (defaultExtraData == null ? "" : NBTTranslator.INSTANCE.translate(defaultExtraData).toString()); - return this.asOptionalWithDefault(value); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull BlockState defaultValue) { - return this.asOptionalWithDefault(defaultValue, null); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull BlockType defaultValue) { - return this.asOptionalWithDefault(defaultValue.defaultState()); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull DefaultedRegistryReference defaultValue) { - return this.asOptionalWithDefault(defaultValue.get()); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockPredicateArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockPredicateArgument.java deleted file mode 100644 index 597fe023..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/BlockPredicateArgument.java +++ /dev/null @@ -1,215 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.BlockPredicate; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.world.server.ServerLocation; -import org.spongepowered.common.util.VecHelper; - -/** - * An argument for parsing {@link BlockPredicate BlockPredicates}. - * - * @param sender type - */ -public final class BlockPredicateArgument extends CommandArgument { - - private BlockPredicateArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - BlockPredicate.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link BlockPredicateArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link BlockPredicateArgument} - */ - public static @NonNull BlockPredicateArgument of(final @NonNull String name) { - return BlockPredicateArgument.builder(name).build(); - } - - /** - * Create a new optional {@link BlockPredicateArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link BlockPredicateArgument} - */ - public static @NonNull BlockPredicateArgument optional(final @NonNull String name) { - return BlockPredicateArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link BlockPredicate}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser( - net.minecraft.commands.arguments.blocks.BlockPredicateArgument.blockPredicate() - ).map((ctx, result) -> { - final CommandSourceStack commandSourceStack = - (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE); - try { - return ArgumentParseResult.success( - new BlockPredicateImpl(result.create(commandSourceStack.getLevel().getTagManager())) - ); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); - - @Override - public @NonNull ArgumentParseResult<@NonNull BlockPredicate> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.BLOCK_PREDICATE.get().createNode(); - } - - private static final class BlockPredicateImpl implements BlockPredicate { - - private final Predicate predicate; - - BlockPredicateImpl(final @NonNull Predicate predicate) { - this.predicate = predicate; - } - - private boolean testImpl(final @NonNull ServerLocation location, final boolean loadChunks) { - return this.predicate.test(new BlockInWorld( - (ServerLevel) location.world(), - VecHelper.toBlockPos(location.position()), - loadChunks - )); - } - - @Override - public boolean test(final @NonNull ServerLocation location) { - return this.testImpl(location, false); - } - - @Override - public @NonNull BlockPredicate loadChunks() { - return new BlockPredicate() { - @Override - public @NonNull BlockPredicate loadChunks() { - return this; - } - - @Override - public boolean test(final @NonNull ServerLocation location) { - return BlockPredicateImpl.this.testImpl(location, true); - } - }; - } - - } - - } - - /** - * Builder for {@link BlockPredicateArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(BlockPredicate.class, name); - } - - @Override - public @NonNull BlockPredicateArgument build() { - return new BlockPredicateArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ComponentArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ComponentArgument.java deleted file mode 100644 index e7f75371..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ComponentArgument.java +++ /dev/null @@ -1,181 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.ComponentLike; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.common.adventure.SpongeAdventure; - -/** - * An argument for parsing {@link Component Components} from json formatted text. - * - * @param sender type - */ -public final class ComponentArgument extends CommandArgument { - - private ComponentArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - Component.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link ComponentArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ComponentArgument} - */ - public static @NonNull ComponentArgument of(final @NonNull String name) { - return ComponentArgument.builder(name).build(); - } - - /** - * Create a new optional {@link ComponentArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ComponentArgument} - */ - public static @NonNull ComponentArgument optional(final @NonNull String name) { - return ComponentArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link ComponentArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link ComponentArgument} - */ - public static @NonNull ComponentArgument optional( - final @NonNull String name, - final @NonNull ComponentLike defaultValue - ) { - return ComponentArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link Component Components} from json formatted text. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser( - net.minecraft.commands.arguments.ComponentArgument.textComponent() - ).map((ctx, component) -> - ArgumentParseResult.success(SpongeAdventure.asAdventure(component))); - - @Override - public @NonNull ArgumentParseResult<@NonNull Component> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.COMPONENT.get().createNode(); - } - - } - - /** - * Builder for {@link ComponentArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(Component.class, name); - } - - @Override - public @NonNull ComponentArgument build() { - return new ComponentArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull ComponentLike defaultValue) { - return this.asOptionalWithDefault(GsonComponentSerializer.gson().serialize(defaultValue.asComponent())); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/DataContainerArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/DataContainerArgument.java deleted file mode 100644 index fcee3574..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/DataContainerArgument.java +++ /dev/null @@ -1,181 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.arguments.CompoundTagArgument; -import net.minecraft.nbt.CompoundTag; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.data.persistence.DataContainer; -import org.spongepowered.common.data.persistence.NBTTranslator; - -/** - * Argument for parsing {@link DataContainer DataContainers} from - * SNBT strings. - * - * @param sender type - */ -public final class DataContainerArgument extends CommandArgument { - - private DataContainerArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - DataContainer.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link DataContainerArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link DataContainerArgument} - */ - public static @NonNull DataContainerArgument of(final @NonNull String name) { - return DataContainerArgument.builder(name).build(); - } - - /** - * Create a new optional {@link DataContainerArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link DataContainerArgument} - */ - public static @NonNull DataContainerArgument optional(final @NonNull String name) { - return DataContainerArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link DataContainerArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link DataContainerArgument} - */ - public static @NonNull DataContainerArgument optional( - final @NonNull String name, - final @NonNull DataContainer defaultValue - ) { - return DataContainerArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link DataContainer DataContainers} from SNBT. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser(CompoundTagArgument.compoundTag()) - .map((ctx, compoundTag) -> - ArgumentParseResult.success(NBTTranslator.INSTANCE.translate(compoundTag))); - - @Override - public @NonNull ArgumentParseResult<@NonNull DataContainer> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.NBT_COMPOUND_TAG.get().createNode(); - } - - } - - /** - * Builder for {@link DataContainerArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(DataContainer.class, name); - } - - @Override - public @NonNull DataContainerArgument build() { - return new DataContainerArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull DataContainer defaultValue) { - return this.asOptionalWithDefault(NBTTranslator.INSTANCE.translate(defaultValue).toString()); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileArgument.java deleted file mode 100644 index 97a8f613..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileArgument.java +++ /dev/null @@ -1,198 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.exceptions.parsing.ParserException; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCaptionKeys; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.Collection; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.profile.GameProfile; -import org.spongepowered.common.profile.SpongeGameProfile; - -/** - * Argument for parsing a single {@link GameProfile} from a {@link Selector}. - * - * @param sender type - */ -public final class GameProfileArgument extends CommandArgument { - - private GameProfileArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - GameProfile.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link GameProfileArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link GameProfileArgument} - */ - public static @NonNull GameProfileArgument of(final @NonNull String name) { - return GameProfileArgument.builder(name).build(); - } - - /** - * Create a new optional {@link GameProfileArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link GameProfileArgument} - */ - public static @NonNull GameProfileArgument optional(final @NonNull String name) { - return GameProfileArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Create a new parser for a single {@link GameProfile}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser( - net.minecraft.commands.arguments.GameProfileArgument.gameProfile() - ).map((ctx, argumentResult) -> { - final Collection profiles; - try { - profiles = argumentResult.getNames( - (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) - ); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - if (profiles.size() > 1) { - return ArgumentParseResult.failure(new TooManyGameProfilesSelectedException(ctx)); - } - final GameProfile profile = SpongeGameProfile.of(profiles.iterator().next()); - return ArgumentParseResult.success(profile); - }); - - @Override - public @NonNull ArgumentParseResult<@NonNull GameProfile> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.GAME_PROFILE.get().createNode(); - } - - } - - /** - * Builder for {@link GameProfileArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(GameProfile.class, name); - } - - @Override - public @NonNull GameProfileArgument build() { - return new GameProfileArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - /** - * Exception thrown when too many game profiles are selected. - */ - private static final class TooManyGameProfilesSelectedException extends ParserException { - - private static final long serialVersionUID = -2931411139985042222L; - - TooManyGameProfilesSelectedException(final @NonNull CommandContext context) { - super( - Parser.class, - context, - SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileCollectionArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileCollectionArgument.java deleted file mode 100644 index f841e9ec..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/GameProfileCollectionArgument.java +++ /dev/null @@ -1,212 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.GameProfileCollection; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.AbstractCollection; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import net.minecraft.commands.CommandSourceStack; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.profile.GameProfile; -import org.spongepowered.common.profile.SpongeGameProfile; - -/** - * Argument for parsing a {@link Collection} of {@link GameProfile GameProfiles} from a - * {@link Selector}. A successfully parsed result will contain at least one element. - * - * @param sender type - */ -public final class GameProfileCollectionArgument extends CommandArgument { - - private GameProfileCollectionArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - GameProfileCollection.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link GameProfileArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link GameProfileArgument} - */ - public static @NonNull GameProfileCollectionArgument of(final @NonNull String name) { - return GameProfileCollectionArgument.builder(name).build(); - } - - /** - * Create a new optional {@link GameProfileArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link GameProfileArgument} - */ - public static @NonNull GameProfileCollectionArgument optional(final @NonNull String name) { - return GameProfileCollectionArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for a {@link Collection} of {@link GameProfile GameProfiles}. A successfully parsed result will - * contain at least one element. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser( - net.minecraft.commands.arguments.GameProfileArgument.gameProfile() - ).map((ctx, argumentResult) -> { - final Collection profiles; - try { - profiles = argumentResult.getNames( - (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) - ); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - final List result = profiles.stream() - .map(SpongeGameProfile::of).collect(Collectors.toList()); - return ArgumentParseResult.success(new GameProfileCollectionImpl(Collections.unmodifiableCollection(result))); - }); - - @Override - public @NonNull ArgumentParseResult<@NonNull GameProfileCollection> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.GAME_PROFILE.get().createNode(); - } - - } - - /** - * Builder for {@link GameProfileCollectionArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(GameProfileCollection.class, name); - } - - @Override - public @NonNull GameProfileCollectionArgument build() { - return new GameProfileCollectionArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - @DefaultQualifier(NonNull.class) - private static final class GameProfileCollectionImpl extends AbstractCollection - implements GameProfileCollection { - - private final Collection backing; - - private GameProfileCollectionImpl(final Collection backing) { - this.backing = backing; - } - - @Override - public int size() { - return this.backing.size(); - } - - @Override - public Iterator iterator() { - return this.backing.iterator(); - } - - @Override - public boolean add(final GameProfile gameProfile) { - return this.backing.add(gameProfile); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ItemStackPredicateArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ItemStackPredicateArgument.java deleted file mode 100644 index 0e108094..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ItemStackPredicateArgument.java +++ /dev/null @@ -1,211 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.ItemStackPredicate; -import com.mojang.brigadier.context.StringRange; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.Collections; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.item.ItemPredicateArgument; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.item.inventory.ItemStack; - -/** - * An argument for parsing {@link ItemStackPredicate ItemStackPredicates}. - * - * @param sender type - */ -public final class ItemStackPredicateArgument extends CommandArgument { - - private ItemStackPredicateArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - ItemStackPredicate.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link ItemStackPredicateArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ItemStackPredicateArgument} - */ - public static @NonNull ItemStackPredicateArgument of(final @NonNull String name) { - return ItemStackPredicateArgument.builder(name).build(); - } - - /** - * Create a new optional {@link ItemStackPredicateArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ItemStackPredicateArgument} - */ - public static @NonNull ItemStackPredicateArgument optional(final @NonNull String name) { - return ItemStackPredicateArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link ItemStackPredicate}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser( - ItemPredicateArgument.itemPredicate() - ).map((ctx, result) -> { - final CommandSourceStack commandSourceStack = - (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE); - try { - final com.mojang.brigadier.context.CommandContext dummyContext = - createDummyContext(ctx, commandSourceStack); - return ArgumentParseResult.success(new ItemStackPredicateImpl(result.create(dummyContext))); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - }); - - @Override - public @NonNull ArgumentParseResult<@NonNull ItemStackPredicate> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.ITEM_PREDICATE.get().createNode(); - } - - private static final class ItemStackPredicateImpl implements ItemStackPredicate { - - private final Predicate predicate; - - ItemStackPredicateImpl(final @NonNull Predicate predicate) { - this.predicate = predicate; - } - - @SuppressWarnings("ConstantConditions") - @Override - public boolean test(final @NonNull ItemStack itemStack) { - return this.predicate.test((net.minecraft.world.item.ItemStack) (Object) itemStack); - } - - } - - private static com.mojang.brigadier.context.@NonNull CommandContext createDummyContext( - final @NonNull CommandContext ctx, - final @NonNull CommandSourceStack commandSourceStack - ) { - return new com.mojang.brigadier.context.CommandContext<>( - commandSourceStack, - ctx.getRawInputJoined(), - Collections.emptyMap(), - null, - null, - Collections.emptyList(), - StringRange.at(0), - null, - null, - false - ); - } - - } - - /** - * Builder for {@link ItemStackPredicateArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(ItemStackPredicate.class, name); - } - - @Override - public @NonNull ItemStackPredicateArgument build() { - return new ItemStackPredicateArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultipleEntitySelectorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultipleEntitySelectorArgument.java deleted file mode 100644 index 5e745ea2..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultipleEntitySelectorArgument.java +++ /dev/null @@ -1,215 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.MultipleEntitySelector; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.Collection; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.selector.EntitySelector; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.entity.Entity; - -/** - * Argument for selecting one or more {@link Entity Entities} using a {@link Selector}. - * - * @param sender type - */ -public final class MultipleEntitySelectorArgument extends CommandArgument { - - private MultipleEntitySelectorArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - MultipleEntitySelector.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link MultipleEntitySelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link MultipleEntitySelectorArgument} - */ - public static @NonNull MultipleEntitySelectorArgument of(final @NonNull String name) { - return MultipleEntitySelectorArgument.builder(name).build(); - } - - /** - * Create a new optional {@link MultipleEntitySelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link MultipleEntitySelectorArgument} - */ - public static @NonNull MultipleEntitySelectorArgument optional(final @NonNull String name) { - return MultipleEntitySelectorArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link MultipleEntitySelector}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.entities()); - - @Override - public @NonNull ArgumentParseResult<@NonNull MultipleEntitySelector> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String originalInput = String.join(" ", inputQueue); - final ArgumentParseResult result = this.nativeParser.parse(commandContext, inputQueue); - if (result.getFailure().isPresent()) { - return ArgumentParseResult.failure(result.getFailure().get()); - } - final String consumedInput = String.join(" ", inputQueue); - final EntitySelector parsed = result.getParsedValue().get(); - final List entities; - try { - entities = parsed.findEntities( - ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) - ).stream().map(e -> (Entity) e).collect(Collectors.toList()); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - final int consumedChars = originalInput.length() - consumedInput.length(); - final String input = originalInput.substring(0, consumedChars); - return ArgumentParseResult.success(new MultipleEntitySelectorImpl((Selector) parsed, input, entities)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.nativeParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.ENTITY.get().createNode(); - } - - } - - /** - * Builder for {@link MultipleEntitySelectorArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(MultipleEntitySelector.class, name); - } - - @Override - public @NonNull MultipleEntitySelectorArgument build() { - return new MultipleEntitySelectorArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - private static final class MultipleEntitySelectorImpl implements MultipleEntitySelector { - - private final Selector selector; - private final String inputString; - private final Collection result; - - private MultipleEntitySelectorImpl( - final Selector selector, - final String inputString, - final Collection result - ) { - this.selector = selector; - this.inputString = inputString; - this.result = result; - } - - @Override - public @NonNull Selector selector() { - return this.selector; - } - - @Override - public @NonNull String inputString() { - return this.inputString; - } - - @Override - public @NonNull Collection get() { - return this.result; - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultiplePlayerSelectorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultiplePlayerSelectorArgument.java deleted file mode 100644 index aefd158f..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/MultiplePlayerSelectorArgument.java +++ /dev/null @@ -1,216 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.MultiplePlayerSelector; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.Collection; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.selector.EntitySelector; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.entity.living.player.server.ServerPlayer; - -/** - * Argument for selecting one or more {@link Player Players} using a {@link Selector}. - * - * @param sender type - */ -public final class MultiplePlayerSelectorArgument extends CommandArgument { - - private MultiplePlayerSelectorArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - MultiplePlayerSelector.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link MultiplePlayerSelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a bew {@link MultiplePlayerSelectorArgument} - */ - public static @NonNull MultiplePlayerSelectorArgument of(final @NonNull String name) { - return MultiplePlayerSelectorArgument.builder(name).build(); - } - - /** - * Create a new optional {@link MultiplePlayerSelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a bew {@link MultiplePlayerSelectorArgument} - */ - public static @NonNull MultiplePlayerSelectorArgument optional(final @NonNull String name) { - return MultiplePlayerSelectorArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link MultiplePlayerSelector}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.players()); - - @Override - public @NonNull ArgumentParseResult<@NonNull MultiplePlayerSelector> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String originalInput = String.join(" ", inputQueue); - final ArgumentParseResult result = this.nativeParser.parse(commandContext, inputQueue); - if (result.getFailure().isPresent()) { - return ArgumentParseResult.failure(result.getFailure().get()); - } - final String consumedInput = String.join(" ", inputQueue); - final EntitySelector parsed = result.getParsedValue().get(); - final List players; - try { - players = parsed.findPlayers( - ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) - ).stream().map(p -> (ServerPlayer) p).collect(Collectors.toList()); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - final int consumedChars = originalInput.length() - consumedInput.length(); - final String input = originalInput.substring(0, consumedChars); - return ArgumentParseResult.success(new MultiplePlayerSelectorImpl((Selector) parsed, input, players)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.nativeParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.ENTITY.get().createNode().playersOnly(); - } - - } - - /** - * Builder for {@link MultiplePlayerSelectorArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(MultiplePlayerSelector.class, name); - } - - @Override - public @NonNull MultiplePlayerSelectorArgument build() { - return new MultiplePlayerSelectorArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - private static final class MultiplePlayerSelectorImpl implements MultiplePlayerSelector { - - private final Selector selector; - private final String inputString; - private final Collection result; - - private MultiplePlayerSelectorImpl( - final Selector selector, - final String inputString, - final Collection result - ) { - this.selector = selector; - this.inputString = inputString; - this.result = result; - } - - @Override - public @NonNull Selector selector() { - return this.selector; - } - - @Override - public @NonNull String inputString() { - return this.inputString; - } - - @Override - public @NonNull Collection get() { - return this.result; - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/NamedTextColorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/NamedTextColorArgument.java deleted file mode 100644 index 9d11581d..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/NamedTextColorArgument.java +++ /dev/null @@ -1,188 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Queue; -import java.util.function.BiFunction; -import net.kyori.adventure.text.format.NamedTextColor; -import net.minecraft.commands.arguments.ColorArgument; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; - -/** - * An argument for parsing {@link NamedTextColor NamedTextColors}. - * - * @param sender type - */ -public final class NamedTextColorArgument extends CommandArgument { - - private NamedTextColorArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - NamedTextColor.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link NamedTextColorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link NamedTextColorArgument} - */ - public static @NonNull NamedTextColorArgument of(final @NonNull String name) { - return NamedTextColorArgument.builder(name).build(); - } - - /** - * Create a new optional {@link NamedTextColorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link NamedTextColorArgument} - */ - public static @NonNull NamedTextColorArgument optional(final @NonNull String name) { - return NamedTextColorArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link NamedTextColorArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link NamedTextColorArgument} - */ - public static @NonNull NamedTextColorArgument optional( - final @NonNull String name, - final @NonNull NamedTextColor defaultValue - ) { - return NamedTextColorArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link NamedTextColor}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - @Override - public @NonNull ArgumentParseResult<@NonNull NamedTextColor> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String input = inputQueue.peek().toLowerCase(Locale.ROOT); - final NamedTextColor color = NamedTextColor.NAMES.value(input); - if (color != null) { - inputQueue.remove(); - return ArgumentParseResult.success(color); - } - return ArgumentParseResult.failure(ColorArgument.ERROR_INVALID_VALUE.create(input)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return new ArrayList<>(NamedTextColor.NAMES.keys()); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.COLOR.get().createNode(); - } - - } - - /** - * Builder for {@link NamedTextColorArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(NamedTextColor.class, name); - } - - @Override - public @NonNull NamedTextColorArgument build() { - return new NamedTextColorArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull NamedTextColor defaultValue) { - return this.asOptionalWithDefault(Objects.requireNonNull(NamedTextColor.NAMES.key(defaultValue))); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/OperatorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/OperatorArgument.java deleted file mode 100644 index c50a6f50..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/OperatorArgument.java +++ /dev/null @@ -1,232 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Optional; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.parameter.managed.operator.Operator; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.registry.DefaultedRegistryReference; -import org.spongepowered.api.registry.RegistryTypes; - -/** - * An argument for parsing {@link Operator Operators}. - * - * @param sender type - */ -public final class OperatorArgument extends CommandArgument { - - private OperatorArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - Operator.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link OperatorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link OperatorArgument} - */ - public static @NonNull OperatorArgument of(final @NonNull String name) { - return OperatorArgument.builder(name).build(); - } - - /** - * Create a new optional {@link OperatorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link OperatorArgument} - */ - public static @NonNull OperatorArgument optional(final @NonNull String name) { - return OperatorArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link OperatorArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link OperatorArgument} - */ - public static @NonNull OperatorArgument optional(final @NonNull String name, final @NonNull Operator defaultValue) { - return OperatorArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link OperatorArgument} with the specified default value. - * - * @param name argument name - * @param sender type - * @param defaultValue default value - * @return a new {@link OperatorArgument} - */ - public static @NonNull OperatorArgument optional( - final @NonNull String name, - final @NonNull DefaultedRegistryReference defaultValue - ) { - return OperatorArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Argument parser for {@link Operator Operators}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private static final SimpleCommandExceptionType ERROR_INVALID_OPERATION; - - static { - try { - // todo: fix in a better way - final Class spongeAccessor = - Class.forName("org.spongepowered.common.accessor.commands.arguments.OperationArgumentAccessor"); - final Method get = spongeAccessor.getDeclaredMethod("accessor$ERROR_INVALID_OPERATION"); - get.setAccessible(true); - ERROR_INVALID_OPERATION = (SimpleCommandExceptionType) get.invoke(null); - } catch (final ReflectiveOperationException ex) { - throw new RuntimeException("Couldn't access ERROR_INVALID_OPERATION command exception type.", ex); - } - } - - @Override - public @NonNull ArgumentParseResult<@NonNull Operator> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String input = inputQueue.peek(); - final Optional operator = RegistryTypes.OPERATOR.get().stream() - .filter(op -> op.asString().equals(input)) - .findFirst(); - if (!operator.isPresent()) { - return ArgumentParseResult.failure(ERROR_INVALID_OPERATION.create()); - } - inputQueue.remove(); - return ArgumentParseResult.success(operator.get()); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return RegistryTypes.OPERATOR.get().stream() - .map(Operator::asString) - .collect(Collectors.toList()); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.OPERATION.get().createNode(); - } - - } - - /** - * Builder for {@link OperatorArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(Operator.class, name); - } - - @Override - public @NonNull OperatorArgument build() { - return new OperatorArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull Operator defaultValue) { - return this.asOptionalWithDefault(defaultValue.asString()); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull DefaultedRegistryReference defaultValue) { - return this.asOptionalWithDefault(defaultValue.get().asString()); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ProtoItemStackArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ProtoItemStackArgument.java deleted file mode 100644 index 2f7f1449..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ProtoItemStackArgument.java +++ /dev/null @@ -1,346 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.data.ProtoItemStack; -import cloud.commandframework.sponge.exception.ComponentMessageRuntimeException; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.kyori.adventure.util.ComponentMessageThrowable; -import net.minecraft.commands.arguments.item.ItemArgument; -import net.minecraft.commands.arguments.item.ItemInput; -import net.minecraft.nbt.CompoundTag; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.data.persistence.DataContainer; -import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.api.registry.DefaultedRegistryReference; -import org.spongepowered.common.data.persistence.NBTTranslator; - -/** - * An argument for parsing {@link ProtoItemStack ProtoItemStacks} from an {@link ItemType} identifier - * and optional NBT data. - * - *

Example input strings:

- *
    - *
  • {@code apple}
  • - *
  • {@code minecraft:apple}
  • - *
  • {@code diamond_sword{Enchantments:[{id:sharpness,lvl:5}]}}
  • - *
- * - * @param sender type - */ -public final class ProtoItemStackArgument extends CommandArgument { - - private ProtoItemStackArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - ProtoItemStack.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link ProtoItemStackArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ProtoItemStackArgument} - */ - public static @NonNull ProtoItemStackArgument of(final @NonNull String name) { - return ProtoItemStackArgument.builder(name).build(); - } - - /** - * Create a new optional {@link ProtoItemStackArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ProtoItemStackArgument} - */ - public static @NonNull ProtoItemStackArgument optional(final @NonNull String name) { - return ProtoItemStackArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link ProtoItemStackArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link ProtoItemStackArgument} - */ - public static @NonNull ProtoItemStackArgument optional( - final @NonNull String name, - final @NonNull ItemStackSnapshot defaultValue - ) { - return ProtoItemStackArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link ProtoItemStackArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link ProtoItemStackArgument} - */ - public static @NonNull ProtoItemStackArgument optional( - final @NonNull String name, - final @NonNull ItemStack defaultValue - ) { - return ProtoItemStackArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link ProtoItemStackArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link ProtoItemStackArgument} - */ - public static @NonNull ProtoItemStackArgument optional( - final @NonNull String name, - final @NonNull ItemType defaultValue - ) { - return ProtoItemStackArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link ProtoItemStackArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link ProtoItemStackArgument} - */ - public static @NonNull ProtoItemStackArgument optional( - final @NonNull String name, - final @NonNull DefaultedRegistryReference defaultValue - ) { - return ProtoItemStackArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link ItemStackSnapshot ItemStackSnapshots} from an {@link ItemType} identifier and - * optional NBT data. The stack size of the resulting snapshot will always be {@code 1}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser(ItemArgument.item()) - .map((ctx, itemInput) -> ArgumentParseResult.success(new ProtoItemStackImpl(itemInput))); - - @Override - public @NonNull ArgumentParseResult<@NonNull ProtoItemStack> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.ITEM_STACK.get().createNode(); - } - - private static final class ProtoItemStackImpl implements ProtoItemStack { - - // todo: use accessor - private static final Field COMPOUND_TAG_FIELD = - Arrays.stream(ItemInput.class.getDeclaredFields()) - .filter(f -> f.getType().equals(CompoundTag.class)) - .findFirst() - .orElseThrow(IllegalStateException::new); - - static { - COMPOUND_TAG_FIELD.setAccessible(true); - } - - private final ItemInput itemInput; - private final @Nullable DataContainer extraData; - - ProtoItemStackImpl(final @NonNull ItemInput itemInput) { - this.itemInput = itemInput; - try { - final CompoundTag tag = (CompoundTag) COMPOUND_TAG_FIELD.get(itemInput); - this.extraData = tag == null ? null : NBTTranslator.INSTANCE.translate(tag); - } catch (final IllegalAccessException ex) { - throw new RuntimeException(ex); - } - } - - @Override - public @NonNull ItemType itemType() { - return (ItemType) this.itemInput.getItem(); - } - - @Override - public @Nullable DataContainer extraData() { - return this.extraData; - } - - @SuppressWarnings("ConstantConditions") - @Override - public @NonNull ItemStack createItemStack( - final int stackSize, - final boolean respectMaximumStackSize - ) throws ComponentMessageRuntimeException { - try { - return (ItemStack) (Object) this.itemInput.createItemStack(stackSize, respectMaximumStackSize); - } catch (final CommandSyntaxException ex) { - throw new ComponentMessageRuntimeException(ComponentMessageThrowable.getMessage(ex), ex); - } - } - - @Override - public @NonNull ItemStackSnapshot createItemStackSnapshot( - final int stackSize, - final boolean respectMaximumStackSize - ) throws ComponentMessageRuntimeException { - return this.createItemStack(stackSize, respectMaximumStackSize).createSnapshot(); - } - - } - - } - - /** - * Builder for {@link ProtoItemStackArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(ProtoItemStack.class, name); - } - - @Override - public @NonNull ProtoItemStackArgument build() { - return new ProtoItemStackArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull ItemType defaultValue) { - return this.asOptionalWithDefault(ItemStack.of(defaultValue)); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull DefaultedRegistryReference defaultValue) { - return this.asOptionalWithDefault(defaultValue.get()); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull ItemStackSnapshot defaultValue) { - return this.asOptionalWithDefault(defaultValue.createStack()); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - @SuppressWarnings("ConstantConditions") - public @NonNull Builder asOptionalWithDefault(final @NonNull ItemStack defaultValue) { - final net.minecraft.world.item.ItemStack stack = (net.minecraft.world.item.ItemStack) (Object) defaultValue; - return this.asOptionalWithDefault(new ItemInput(stack.getItem(), stack.getTag()).serialize()); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/RegistryEntryArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/RegistryEntryArgument.java deleted file mode 100644 index 2161c90a..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/RegistryEntryArgument.java +++ /dev/null @@ -1,617 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.captions.CaptionVariable; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.exceptions.parsing.ParserException; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCaptionKeys; -import io.leangen.geantyref.TypeToken; -import java.util.List; -import java.util.Optional; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.command.registrar.tree.CommandCompletionProviders; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.registry.DefaultedRegistryType; -import org.spongepowered.api.registry.Registry; -import org.spongepowered.api.registry.RegistryEntry; -import org.spongepowered.api.registry.RegistryHolder; -import org.spongepowered.api.registry.RegistryReference; -import org.spongepowered.api.registry.RegistryType; -import org.spongepowered.api.registry.RegistryTypes; - -/** - * An argument for retrieving values from any of Sponge's {@link Registry Registries}. - * - * @param sender type - * @param value type - */ -public final class RegistryEntryArgument extends CommandArgument { - - private RegistryEntryArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @NonNull TypeToken valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(holderSupplier, registryType), - defaultValue, - valueType, - suggestionsProvider, - defaultDescription - ); - } - - // Start DefaultedRegistryType methods - - /** - * Create a new required {@link RegistryEntryArgument} for a {@link DefaultedRegistryType}. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument of( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull DefaultedRegistryType registryType - ) { - return RegistryEntryArgument.builder(name, valueType, registryType).build(); - } - - /** - * Create a new required {@link RegistryEntryArgument} for a {@link DefaultedRegistryType}. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument of( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull DefaultedRegistryType registryType - ) { - return of(name, TypeToken.get(valueType), registryType); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link DefaultedRegistryType}. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull DefaultedRegistryType registryType - ) { - return RegistryEntryArgument.builder(name, valueType, registryType).asOptional().build(); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link DefaultedRegistryType}. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull DefaultedRegistryType registryType - ) { - return optional(name, TypeToken.get(valueType), registryType); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link DefaultedRegistryType}, - * with the specified default value. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param defaultValue default value - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull DefaultedRegistryType registryType, - final @NonNull RegistryReference defaultValue - ) { - return RegistryEntryArgument.builder(name, valueType, registryType) - .asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link DefaultedRegistryType}, - * with the specified default value. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param defaultValue default value - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull DefaultedRegistryType registryType, - final @NonNull RegistryReference defaultValue - ) { - return optional(name, TypeToken.get(valueType), registryType, defaultValue); - } - - /** - * Create a new {@link Builder} for a {@link DefaultedRegistryType}. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull DefaultedRegistryType registryType - ) { - return new Builder<>(name, valueType, ctx -> registryType.defaultHolder().get(), registryType); - } - - /** - * Create a new {@link Builder} for a {@link DefaultedRegistryType}. - * - * @param name argument name - * @param valueType value type - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull DefaultedRegistryType registryType - ) { - return builder(name, TypeToken.get(valueType), registryType); - } - - // End DefaultedRegistryType methods - - // Start RegistryType methods - - /** - * Create a new required {@link RegistryEntryArgument} for a {@link RegistryType} - * using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #of(String, TypeToken, DefaultedRegistryType)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument of( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - return RegistryEntryArgument.builder(name, valueType, holderSupplier, registryType).build(); - } - - /** - * Create a new required {@link RegistryEntryArgument} for a {@link RegistryType} - * using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #of(String, Class, DefaultedRegistryType)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument of( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - return of(name, TypeToken.get(valueType), holderSupplier, registryType); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link RegistryType} - * using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #optional(String, TypeToken, DefaultedRegistryType)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - return builder(name, valueType, holderSupplier, registryType).asOptional().build(); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link RegistryType} - * using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #optional(String, Class, DefaultedRegistryType)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - return optional(name, TypeToken.get(valueType), holderSupplier, registryType); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link RegistryType} - * using the specified {@link RegistryHolder} function and default value. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #optional(String, Class, DefaultedRegistryType, RegistryReference)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param defaultValue default value - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType, - final @NonNull RegistryReference defaultValue - ) { - return optional(name, TypeToken.get(valueType), holderSupplier, registryType, defaultValue); - } - - /** - * Create a new optional {@link RegistryEntryArgument} for a {@link RegistryType} - * using the specified {@link RegistryHolder} function and default value. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #optional(String, TypeToken, DefaultedRegistryType, RegistryReference)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param defaultValue default value - * @param sender type - * @param value type - * @return a new {@link RegistryEntryArgument} - */ - public static @NonNull RegistryEntryArgument optional( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType, - final @NonNull RegistryReference defaultValue - ) { - return builder(name, valueType, holderSupplier, registryType).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder} using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #builder(String, TypeToken, DefaultedRegistryType)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - return new Builder<>(name, valueType, holderSupplier, registryType); - } - - /** - * Create a new {@link Builder} using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #builder(String, Class, DefaultedRegistryType)}.

- * - * @param name argument name - * @param valueType value type - * @param holderSupplier registry holder function - * @param registryType registry type - * @param sender type - * @param value type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder( - final @NonNull String name, - final @NonNull Class valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - return builder(name, TypeToken.get(valueType), holderSupplier, registryType); - } - - // End RegistryType methods - - /** - * An argument parser for values in a {@link Registry}. - * - * @param sender type - * @param value type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final Function, RegistryHolder> holderSupplier; - private final RegistryType registryType; - - /** - * Create a new {@link Parser} using the specified {@link RegistryHolder} function. - * - *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, - * it is suggested to instead use {@link #Parser(DefaultedRegistryType)}.

- * - * @param holderSupplier registry holder function - * @param registryType registry type - */ - public Parser( - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - this.holderSupplier = holderSupplier; - this.registryType = registryType; - } - - /** - * Create a new {@link Parser}. - * - * @param registryType defaulted registry type - */ - public Parser(final @NonNull DefaultedRegistryType registryType) { - this(ctx -> registryType.defaultHolder().get(), registryType); - } - - private Registry registry(final @NonNull CommandContext commandContext) { - return this.holderSupplier.apply(commandContext).registry(this.registryType); - } - - @Override - public @NonNull ArgumentParseResult<@NonNull V> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String input = inputQueue.peek(); - final ResourceKey key = ResourceKeyUtil.resourceKey(input); - if (key == null) { - return ResourceKeyUtil.invalidResourceKey(); - } - final Optional> entry = this.registry(commandContext).findEntry(key); - if (entry.isPresent()) { - inputQueue.remove(); - return ArgumentParseResult.success(entry.get().value()); - } - return ArgumentParseResult.failure(new NoSuchEntryException(commandContext, key, this.registryType)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.registry(commandContext).streamEntries().flatMap(entry -> { - if (!input.isEmpty() && entry.key().namespace().equals(ResourceKey.MINECRAFT_NAMESPACE)) { - return Stream.of(entry.key().value(), entry.key().asString()); - } - return Stream.of(entry.key().asString()); - }).collect(Collectors.toList()); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - if (this.registryType.equals(RegistryTypes.SOUND_TYPE)) { - return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode() - .completions(CommandCompletionProviders.AVAILABLE_SOUNDS); - } else if (this.registryType.equals(RegistryTypes.BIOME)) { - return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode() - .completions(CommandCompletionProviders.AVAILABLE_BIOMES); - } else if (this.registryType.equals(RegistryTypes.ENTITY_TYPE)) { - return CommandTreeNodeTypes.ENTITY_SUMMON.get().createNode() - .completions(CommandCompletionProviders.SUMMONABLE_ENTITIES); - } else if (this.registryType.equals(RegistryTypes.ENCHANTMENT_TYPE)) { - return CommandTreeNodeTypes.ITEM_ENCHANTMENT.get().createNode(); - } else if (this.registryType.equals(RegistryTypes.POTION_EFFECT_TYPE)) { - return CommandTreeNodeTypes.MOB_EFFECT.get().createNode(); - } else if (this.registryType.equals(RegistryTypes.WORLD_TYPE)) { - return CommandTreeNodeTypes.DIMENSION.get().createNode() - .customCompletions(); // Sponge adds custom types (?) - } - return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode().customCompletions(); - } - - } - - /** - * Builder for {@link RegistryEntryArgument}. - * - * @param sender type - * @param value type - */ - public static final class Builder extends TypedBuilder> { - - private final RegistryType registryType; - private final Function, RegistryHolder> holderSupplier; - - Builder( - final @NonNull String name, - final @NonNull TypeToken valueType, - final @NonNull Function, RegistryHolder> holderSupplier, - final @NonNull RegistryType registryType - ) { - super(valueType, name); - this.registryType = registryType; - this.holderSupplier = holderSupplier; - } - - @Override - public @NonNull RegistryEntryArgument build() { - return new RegistryEntryArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getValueType(), - this.holderSupplier, - this.registryType, - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull ResourceKey defaultValue) { - return this.asOptionalWithDefault(defaultValue.asString()); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull RegistryReference defaultValue) { - return this.asOptionalWithDefault(defaultValue.location()); - } - - } - - /** - * An exception thrown when there is no entry for the provided {@link ResourceKey} in the resolved registry. - */ - private static final class NoSuchEntryException extends ParserException { - - private static final long serialVersionUID = 4472876671109079272L; - - NoSuchEntryException( - final CommandContext context, - final ResourceKey key, - final RegistryType registryType - ) { - super( - Parser.class, - context, - SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY, - CaptionVariable.of("id", key.asString()), - CaptionVariable.of("registry", registryType.location().asString()) - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyArgument.java deleted file mode 100644 index d770ca6d..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyArgument.java +++ /dev/null @@ -1,176 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; - -/** - * Argument for parsing {@link ResourceKey ResourceKeys}. - * - * @param sender type - */ -public final class ResourceKeyArgument extends CommandArgument { - - private ResourceKeyArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - ResourceKey.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new optional {@link ResourceKeyArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ResourceKeyArgument} - */ - public static @NonNull ResourceKeyArgument optional(final @NonNull String name) { - return ResourceKeyArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link ResourceKeyArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link ResourceKeyArgument} - */ - public static @NonNull ResourceKeyArgument optional( - final @NonNull String name, - final @NonNull ResourceKey defaultValue - ) { - return ResourceKeyArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new required {@link ResourceKeyArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link ResourceKeyArgument} - */ - public static @NonNull ResourceKeyArgument of(final @NonNull String name) { - return ResourceKeyArgument.builder(name).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Argument parser for {@link ResourceKey ResourceKey}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - @Override - public @NonNull ArgumentParseResult<@NonNull ResourceKey> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String input = inputQueue.peek(); - final ResourceKey key = ResourceKeyUtil.resourceKey(input); - if (key == null) { - return ResourceKeyUtil.invalidResourceKey(); - } - inputQueue.remove(); - return ArgumentParseResult.success(key); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode(); - } - - } - - /** - * Builder for {@link ResourceKeyArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(ResourceKey.class, name); - } - - @Override - public @NonNull ResourceKeyArgument build() { - return new ResourceKeyArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull ResourceKey defaultValue) { - return this.asOptionalWithDefault(defaultValue.asString()); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SingleEntitySelectorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SingleEntitySelectorArgument.java deleted file mode 100644 index 883e706a..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SingleEntitySelectorArgument.java +++ /dev/null @@ -1,213 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.SingleEntitySelector; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.selector.EntitySelector; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.entity.Entity; - -/** - * Argument for selecting a single {@link Entity} using a {@link Selector}. - * - * @param sender type - */ -public final class SingleEntitySelectorArgument extends CommandArgument { - - private SingleEntitySelectorArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - SingleEntitySelector.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link SingleEntitySelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link SingleEntitySelectorArgument} - */ - public static @NonNull SingleEntitySelectorArgument of(final @NonNull String name) { - return SingleEntitySelectorArgument.builder(name).build(); - } - - /** - * Create a new optional {@link SingleEntitySelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link SingleEntitySelectorArgument} - */ - public static @NonNull SingleEntitySelectorArgument optional(final @NonNull String name) { - return SingleEntitySelectorArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link SingleEntitySelector}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.entity()); - - @Override - public @NonNull ArgumentParseResult<@NonNull SingleEntitySelector> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String originalInput = String.join(" ", inputQueue); - final ArgumentParseResult result = this.nativeParser.parse(commandContext, inputQueue); - if (result.getFailure().isPresent()) { - return ArgumentParseResult.failure(result.getFailure().get()); - } - final String consumedInput = String.join(" ", inputQueue); - final EntitySelector parsed = result.getParsedValue().get(); - final Entity entity; - try { - entity = (Entity) parsed.findSingleEntity( - ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) - ); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - final int consumedChars = originalInput.length() - consumedInput.length(); - final String input = originalInput.substring(0, consumedChars); - return ArgumentParseResult.success(new SingleEntitySelectorImpl((Selector) parsed, input, entity)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.nativeParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.ENTITY.get().createNode().single(); - } - - } - - /** - * Builder for {@link SingleEntitySelectorArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(SingleEntitySelector.class, name); - } - - @Override - public @NonNull SingleEntitySelectorArgument build() { - return new SingleEntitySelectorArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - private static final class SingleEntitySelectorImpl implements SingleEntitySelector { - - private final Selector selector; - private final String inputString; - private final Entity result; - - private SingleEntitySelectorImpl( - final Selector selector, - final String inputString, - final Entity result - ) { - this.selector = selector; - this.inputString = inputString; - this.result = result; - } - - @Override - public @NonNull Selector selector() { - return this.selector; - } - - @Override - public @NonNull String inputString() { - return this.inputString; - } - - @Override - public @NonNull Entity getSingle() { - return this.result; - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SinglePlayerSelectorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SinglePlayerSelectorArgument.java deleted file mode 100644 index e4287cf6..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/SinglePlayerSelectorArgument.java +++ /dev/null @@ -1,215 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import cloud.commandframework.sponge.data.SinglePlayerSelector; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.selector.EntitySelector; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.entity.living.player.server.ServerPlayer; - -/** - * Argument for selecting a single {@link Player} using a {@link Selector}. - * - * @param sender type - */ -public final class SinglePlayerSelectorArgument extends CommandArgument { - - private SinglePlayerSelectorArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - SinglePlayerSelector.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link SinglePlayerSelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link SinglePlayerSelectorArgument} - */ - public static @NonNull SinglePlayerSelectorArgument of(final @NonNull String name) { - return SinglePlayerSelectorArgument.builder(name).build(); - } - - /** - * Create a new optional {@link SinglePlayerSelectorArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link SinglePlayerSelectorArgument} - */ - public static @NonNull SinglePlayerSelectorArgument optional(final @NonNull String name) { - return SinglePlayerSelectorArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link SinglePlayerSelector}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.player()); - - @Override - public @NonNull ArgumentParseResult<@NonNull SinglePlayerSelector> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String originalInput = String.join(" ", inputQueue); - final ArgumentParseResult result = this.nativeParser.parse(commandContext, inputQueue); - if (result.getFailure().isPresent()) { - return ArgumentParseResult.failure(result.getFailure().get()); - } - final String consumedInput = String.join(" ", inputQueue); - final EntitySelector parsed = result.getParsedValue().get(); - final ServerPlayer player; - try { - // todo: a more proper fix then setting permission level 2 - player = (ServerPlayer) parsed.findSinglePlayer( - ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) - ); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - final int consumedChars = originalInput.length() - consumedInput.length(); - final String input = originalInput.substring(0, consumedChars); - return ArgumentParseResult.success(new SinglePlayerSelectorImpl((Selector) parsed, input, player)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.nativeParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.ENTITY.get().createNode().playersOnly().single(); - } - - } - - /** - * Builder for {@link SinglePlayerSelectorArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(SinglePlayerSelector.class, name); - } - - @Override - public @NonNull SinglePlayerSelectorArgument build() { - return new SinglePlayerSelectorArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - private static final class SinglePlayerSelectorImpl implements SinglePlayerSelector { - - private final Selector selector; - private final String inputString; - private final ServerPlayer result; - - private SinglePlayerSelectorImpl( - final Selector selector, - final String inputString, - final ServerPlayer result - ) { - this.selector = selector; - this.inputString = inputString; - this.result = result; - } - - @Override - public @NonNull Selector selector() { - return this.selector; - } - - @Override - public @NonNull String inputString() { - return this.inputString; - } - - @Override - public @NonNull ServerPlayer getSingle() { - return this.result; - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/UserArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/UserArgument.java deleted file mode 100644 index c449564c..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/UserArgument.java +++ /dev/null @@ -1,282 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.captions.Caption; -import cloud.commandframework.captions.CaptionVariable; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.exceptions.parsing.ParserException; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCaptionKeys; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Queue; -import java.util.UUID; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.selector.EntitySelector; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.command.selector.Selector; -import org.spongepowered.api.entity.living.player.User; -import org.spongepowered.api.entity.living.player.server.ServerPlayer; -import org.spongepowered.api.profile.GameProfile; -import org.spongepowered.api.user.UserManager; - -/** - * Argument for parsing {@link User} {@link UUID UUIDs} in the {@link UserManager} from - * a {@link Selector}, last known username, or {@link UUID} string. - * - * @param sender type - */ -public final class UserArgument extends CommandArgument { - - private UserArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - UUID.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link UserArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link UserArgument} - */ - public static @NonNull UserArgument of(final @NonNull String name) { - return UserArgument.builder(name).build(); - } - - /** - * Create a new optional {@link UserArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link UserArgument} - */ - public static @NonNull UserArgument optional(final @NonNull String name) { - return UserArgument.builder(name).asOptional().build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link User Users} in the {@link UserManager} by - * {@link Selector}, last known username, or {@link UUID}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser singlePlayerSelectorParser = - new WrappedBrigadierParser<>(EntityArgument.player()); - - @Override - public @NonNull ArgumentParseResult<@NonNull UUID> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String peek = inputQueue.peek(); - if (peek.startsWith("@")) { - return this.handleSelector(commandContext, inputQueue); - } - - try { - final Optional optionalUser = Sponge.server().gameProfileManager().cache().findByName(peek); - // valid username - if (optionalUser.isPresent()) { - inputQueue.remove(); - return ArgumentParseResult.success(optionalUser.get().uniqueId()); - } - return ArgumentParseResult.failure(new UserNotFoundException( - commandContext, UserNotFoundException.Type.NAME, peek - )); - } catch (final IllegalArgumentException ex) { - // not a valid username - } - - try { - final UUID uuid = UUID.fromString(peek); - // valid uuid - if (Sponge.server().userManager().exists(uuid)) { - return ArgumentParseResult.success(uuid); - } - - return ArgumentParseResult.failure(new UserNotFoundException( - commandContext, UserNotFoundException.Type.UUID, peek - )); - } catch (final IllegalArgumentException ex) { - // not a valid uuid - } - - return ArgumentParseResult.failure(new UserNotFoundException( - commandContext, UserNotFoundException.Type.INVALID_INPUT, peek - )); - } - - private @NonNull ArgumentParseResult<@NonNull UUID> handleSelector( - final @NonNull CommandContext<@NonNull C> commandContext, - final @NonNull Queue<@NonNull String> inputQueue - ) { - final ArgumentParseResult result = this.singlePlayerSelectorParser.parse(commandContext, inputQueue); - if (result.getFailure().isPresent()) { - return ArgumentParseResult.failure(result.getFailure().get()); - } - final EntitySelector parsed = result.getParsedValue().get(); - final ServerPlayer player; - try { - player = (ServerPlayer) parsed.findSinglePlayer( - (CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE) - ); - } catch (final CommandSyntaxException ex) { - return ArgumentParseResult.failure(ex); - } - return ArgumentParseResult.success(player.uniqueId()); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - final List suggestions = new ArrayList<>(this.singlePlayerSelectorParser.suggestions(commandContext, input)); - if (!input.startsWith("@")) { - suggestions.addAll(Sponge.server().userManager().streamOfMatches(input) - .filter(GameProfile::hasName) - .map(profile -> profile.name().orElse(null)) - .filter(Objects::nonNull) - .filter(name -> !suggestions.contains(name)) - .collect(Collectors.toList())); - } - return suggestions; - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.GAME_PROFILE.get().createNode().customCompletions(); - } - - } - - /** - * Builder for {@link UserArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(UUID.class, name); - } - - @Override - public @NonNull UserArgument build() { - return new UserArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - } - - /** - * An exception thrown when a {@link User} cannot be found for the provided input. - */ - private static final class UserNotFoundException extends ParserException { - - private static final long serialVersionUID = -24501459406523175L; - - UserNotFoundException( - final CommandContext context, - final @NonNull Type type, - final @NonNull String input - ) { - super( - Parser.class, - context, - type.caption, - type.variable(input) - ); - } - - private enum Type { - UUID("uuid", SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID), - NAME("name", SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME), - INVALID_INPUT("input", SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT); - - private final String key; - private final Caption caption; - - Type(final @NonNull String key, final @NonNull Caption caption) { - this.key = key; - this.caption = caption; - } - - CaptionVariable variable(final @NonNull String input) { - return CaptionVariable.of(this.key, input); - } - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2dArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2dArgument.java deleted file mode 100644 index f091e894..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2dArgument.java +++ /dev/null @@ -1,250 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.coordinates.Coordinates; -import net.minecraft.commands.arguments.coordinates.Vec2Argument; -import net.minecraft.world.phys.Vec3; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.math.vector.Vector2d; - -/** - * Argument for parsing {@link Vector2d} from relative, absolute, or local coordinates. - * - *

Example input strings:

- *
    - *
  • {@code ~ ~}
  • - *
  • {@code 0.1 -0.5}
  • - *
  • {@code ~1 ~-2}
  • - *
- * - * @param sender type - */ -public final class Vector2dArgument extends VectorArgument { - - private Vector2dArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final boolean centerIntegers, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(centerIntegers), - defaultValue, - Vector2d.class, - centerIntegers, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new optional {@link Vector2dArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector2dArgument} - */ - public static @NonNull Vector2dArgument optional(final @NonNull String name) { - return Vector2dArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link Vector2dArgument}. - * - * @param name argument name - * @param centerIntegers whether to center integers to x.5 - * @param sender type - * @return a new {@link Vector2dArgument} - */ - public static @NonNull Vector2dArgument optional(final @NonNull String name, final boolean centerIntegers) { - return Vector2dArgument.builder(name).centerIntegers(centerIntegers).asOptional().build(); - } - - /** - * Create a new optional {@link Vector2dArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link Vector2dArgument} - */ - public static @NonNull Vector2dArgument optional(final @NonNull String name, final @NonNull Vector2d defaultValue) { - return Vector2dArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link Vector2dArgument} with the specified default value. - * - * @param name argument name - * @param centerIntegers whether to center integers to x.5 - * @param defaultValue default value - * @param sender type - * @return a new {@link Vector2dArgument} - */ - public static @NonNull Vector2dArgument optional( - final @NonNull String name, - final boolean centerIntegers, - final @NonNull Vector2d defaultValue - ) { - return Vector2dArgument.builder(name).centerIntegers(centerIntegers).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new required {@link Vector2dArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector2dArgument} - */ - public static @NonNull Vector2dArgument of(final @NonNull String name) { - return Vector2dArgument.builder(name).build(); - } - - /** - * Create a new required {@link Vector2dArgument}. - * - * @param name argument name - * @param centerIntegers whether to center integers to x.5 - * @param sender type - * @return a new {@link Vector2dArgument} - */ - public static @NonNull Vector2dArgument of(final @NonNull String name, final boolean centerIntegers) { - return Vector2dArgument.builder(name).centerIntegers(centerIntegers).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link Vector2d}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser; - - /** - * Create a new {@link Parser}. - * - * @param centerIntegers whether to center integers to x.5 - */ - public Parser(final boolean centerIntegers) { - this.mappedParser = new WrappedBrigadierParser(new Vec2Argument(centerIntegers)) - .map((ctx, coordinates) -> { - final Vec3 position = coordinates.getPosition( - (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) - ); - return ArgumentParseResult.success(new Vector2d(position.x, position.z)); - }); - } - - @Override - public @NonNull ArgumentParseResult<@NonNull Vector2d> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.VEC2.get().createNode(); - } - - } - - /** - * Builder for {@link Vector2dArgument}. - * - * @param sender type - */ - public static final class Builder extends VectorArgumentBuilder> { - - Builder(final @NonNull String name) { - super(Vector2d.class, name); - } - - @Override - public @NonNull Vector2dArgument build() { - return new Vector2dArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.centerIntegers(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull Vector2d defaultValue) { - return this.asOptionalWithDefault(String.format("%.10f %.10f", defaultValue.x(), defaultValue.y())); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2iArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2iArgument.java deleted file mode 100644 index 88af3b56..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector2iArgument.java +++ /dev/null @@ -1,202 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.coordinates.ColumnPosArgument; -import net.minecraft.commands.arguments.coordinates.Coordinates; -import net.minecraft.core.BlockPos; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.math.vector.Vector2i; - -/** - * Argument for parsing {@link Vector2i} from relative, absolute, or local coordinates. - * - *

Example input strings:

- *
    - *
  • {@code ~ ~}
  • - *
  • {@code 12 -7}
  • - *
  • {@code ^-1 ^0}
  • - *
  • {@code ~-1 ~5}
  • - *
  • {@code ^ ^}
  • - *
- * - * @param sender type - */ -public final class Vector2iArgument extends CommandArgument { - - private Vector2iArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - Vector2i.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link Vector2iArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector2iArgument} - */ - public static @NonNull Vector2iArgument of(final @NonNull String name) { - return Vector2iArgument.builder(name).build(); - } - - /** - * Create a new optional {@link Vector2iArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector2iArgument} - */ - public static @NonNull Vector2iArgument optional(final @NonNull String name) { - return Vector2iArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link Vector2iArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link Vector2iArgument} - */ - public static @NonNull Vector2iArgument optional(final @NonNull String name, final @NonNull Vector2i defaultValue) { - return Vector2iArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link Vector2i}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser(ColumnPosArgument.columnPos()) - .map((ctx, coordinates) -> { - final BlockPos pos = coordinates.getBlockPos( - (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) - ); - return ArgumentParseResult.success(new Vector2i(pos.getX(), pos.getZ())); - }); - - @Override - public @NonNull ArgumentParseResult<@NonNull Vector2i> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.COLUMN_POS.get().createNode(); - } - - } - - /** - * Builder for {@link Vector2iArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(Vector2i.class, name); - } - - @Override - public @NonNull Vector2iArgument build() { - return new Vector2iArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull Vector2i defaultValue) { - return this.asOptionalWithDefault( - String.format("%s %s", defaultValue.x(), defaultValue.y()) - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3dArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3dArgument.java deleted file mode 100644 index cea124dd..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3dArgument.java +++ /dev/null @@ -1,252 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.coordinates.Coordinates; -import net.minecraft.commands.arguments.coordinates.Vec3Argument; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.math.vector.Vector3d; - -/** - * Argument for parsing {@link Vector3d} from relative, absolute, or local coordinates. - * - *

Example input strings:

- *
    - *
  • {@code ~ ~ ~}
  • - *
  • {@code 0.1 -0.5 .9}
  • - *
  • {@code ~1 ~-2 ~10}
  • - *
  • {@code ^1 ^ ^-5}
  • - *
- * - * @param sender type - */ -public final class Vector3dArgument extends VectorArgument { - - private Vector3dArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final boolean centerIntegers, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(centerIntegers), - defaultValue, - Vector3d.class, - centerIntegers, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link Vector3dArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector3dArgument} - */ - public static @NonNull Vector3dArgument of(final @NonNull String name) { - return Vector3dArgument.builder(name).build(); - } - - /** - * Create a new required {@link Vector3dArgument}. - * - * @param name argument name - * @param centerIntegers whether to center integers to x.5 - * @param sender type - * @return a new {@link Vector3dArgument} - */ - public static @NonNull Vector3dArgument of(final @NonNull String name, final boolean centerIntegers) { - return Vector3dArgument.builder(name).centerIntegers(centerIntegers).build(); - } - - /** - * Create a new optional {@link Vector3dArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector3dArgument} - */ - public static @NonNull Vector3dArgument optional(final @NonNull String name) { - return Vector3dArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link Vector3dArgument}. - * - * @param name argument name - * @param centerIntegers whether to center integers to x.5 - * @param sender type - * @return a new {@link Vector3dArgument} - */ - public static @NonNull Vector3dArgument optional(final @NonNull String name, final boolean centerIntegers) { - return Vector3dArgument.builder(name).asOptional().centerIntegers(centerIntegers).build(); - } - - /** - * Create a new optional {@link Vector3dArgument}. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link Vector3dArgument} - */ - public static @NonNull Vector3dArgument optional(final @NonNull String name, final @NonNull Vector3d defaultValue) { - return Vector3dArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new optional {@link Vector3dArgument}. - * - * @param name argument name - * @param centerIntegers whether to center integers to x.5 - * @param defaultValue default value - * @param sender type - * @return a new {@link Vector3dArgument} - */ - public static @NonNull Vector3dArgument optional( - final @NonNull String name, - final boolean centerIntegers, - final @NonNull Vector3d defaultValue - ) { - return Vector3dArgument.builder(name).asOptionalWithDefault(defaultValue).centerIntegers(centerIntegers).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link Vector3d}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser; - - /** - * Create a new {@link Parser}. - * - * @param centerIntegers whether to center integers to x.5 - */ - public Parser(final boolean centerIntegers) { - this.mappedParser = new WrappedBrigadierParser(new Vec3Argument(centerIntegers)) - .map((ctx, coordinates) -> { - return ArgumentParseResult.success(VecHelper.toVector3d( - coordinates.getPosition((CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE)) - )); - }); - } - - @Override - public @NonNull ArgumentParseResult<@NonNull Vector3d> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.VEC3.get().createNode(); - } - - } - - /** - * Builder for {@link Vector3dArgument}. - * - * @param sender type - */ - public static final class Builder extends VectorArgumentBuilder> { - - Builder(final @NonNull String name) { - super(Vector3d.class, name); - } - - @Override - public @NonNull Vector3dArgument build() { - return new Vector3dArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.centerIntegers(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull Vector3d defaultValue) { - return this.asOptionalWithDefault( - String.format("%.10f %.10f %.10f", defaultValue.x(), defaultValue.y(), defaultValue.z()) - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3iArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3iArgument.java deleted file mode 100644 index 7d9dce3e..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/Vector3iArgument.java +++ /dev/null @@ -1,200 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import cloud.commandframework.sponge.SpongeCommandContextKeys; -import java.util.List; -import java.util.Queue; -import java.util.function.BiFunction; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.coordinates.BlockPosArgument; -import net.minecraft.commands.arguments.coordinates.Coordinates; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.math.vector.Vector3i; - -/** - * Argument for parsing {@link Vector3i} from relative, absolute, or local coordinates. - * - *

Example input strings:

- *
    - *
  • {@code ~ ~ ~}
  • - *
  • {@code 1 1 1}
  • - *
  • {@code ~0.5 ~-2 ~10}
  • - *
  • {@code ^1 ^ ^-5}
  • - *
- * - * @param sender type - */ -public final class Vector3iArgument extends CommandArgument { - - private Vector3iArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - Vector3i.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link Vector3iArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector3iArgument} - */ - public static @NonNull Vector3iArgument of(final @NonNull String name) { - return Vector3iArgument.builder(name).build(); - } - - /** - * Create a new optional {@link Vector3iArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link Vector3iArgument} - */ - public static @NonNull Vector3iArgument optional(final @NonNull String name) { - return Vector3iArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link Vector3iArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link Vector3iArgument} - */ - public static @NonNull Vector3iArgument optional(final @NonNull String name, final @NonNull Vector3i defaultValue) { - return Vector3iArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link Vector3i}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private final ArgumentParser mappedParser = - new WrappedBrigadierParser(BlockPosArgument.blockPos()) - .map((ctx, coordinates) -> { - return ArgumentParseResult.success(VecHelper.toVector3i( - coordinates.getBlockPos((CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE)) - )); - }); - - @Override - public @NonNull ArgumentParseResult<@NonNull Vector3i> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - return this.mappedParser.parse(commandContext, inputQueue); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return this.mappedParser.suggestions(commandContext, input); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.BLOCK_POS.get().createNode(); - } - - } - - /** - * Builder for {@link Vector3iArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(Vector3i.class, name); - } - - @Override - public @NonNull Vector3iArgument build() { - return new Vector3iArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull Vector3i defaultValue) { - return this.asOptionalWithDefault( - String.format("%s %s %s", defaultValue.x(), defaultValue.y(), defaultValue.z()) - ); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/VectorArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/VectorArgument.java deleted file mode 100644 index 16c40c26..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/VectorArgument.java +++ /dev/null @@ -1,110 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParser; -import cloud.commandframework.context.CommandContext; -import java.util.List; -import java.util.function.BiFunction; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Parent of {@link Vector3dArgument} and {@link Vector2dArgument} containing shared methods. - * - *

Not for extension by API users.

- * - * @param sender type - * @param vector type - */ -public abstract class VectorArgument extends CommandArgument { - - private final boolean centerIntegers; - - protected VectorArgument( - final boolean required, - final @NonNull String name, - final @NonNull ArgumentParser parser, - final @NonNull String defaultValue, - final @NonNull Class vectorType, - final boolean centerIntegers, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super(required, name, parser, defaultValue, vectorType, suggestionsProvider, defaultDescription); - this.centerIntegers = centerIntegers; - } - - /** - * Get whether integers will be centered to x.5. Defaults to false. - * - * @return whether integers will be centered - */ - public boolean centerIntegers() { - return this.centerIntegers; - } - - /** - * Parent of {@link Vector3dArgument.Builder} and {@link Vector2dArgument.Builder}. - * - *

Not for extension by API users.

- * - * @param sender type - * @param vector type - * @param builder subtype - */ - public abstract static class VectorArgumentBuilder> - extends TypedBuilder { - - private boolean centerIntegers = false; - - protected VectorArgumentBuilder(final @NonNull Class vectorClass, final @NonNull String name) { - super(vectorClass, name); - } - - /** - * Set whether integers will be centered to x.5. Will be false by default if unset. - * - * @param centerIntegers whether integers will be centered - * @return this builder - */ - public @NonNull B centerIntegers(final boolean centerIntegers) { - this.centerIntegers = centerIntegers; - return this.self(); - } - - /** - * Get whether integers will be centered to x.5. Defaults to false. - * - * @return whether integers will be centered - */ - public boolean centerIntegers() { - return this.centerIntegers; - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/WorldArgument.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/WorldArgument.java deleted file mode 100644 index a9ab5965..00000000 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/WorldArgument.java +++ /dev/null @@ -1,216 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2022 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.sponge.argument; - -import cloud.commandframework.ArgumentDescription; -import cloud.commandframework.arguments.CommandArgument; -import cloud.commandframework.arguments.parser.ArgumentParseResult; -import cloud.commandframework.context.CommandContext; -import cloud.commandframework.sponge.NodeSupplyingArgumentParser; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.Queue; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import net.minecraft.commands.arguments.DimensionArgument; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.registrar.tree.CommandTreeNode; -import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; -import org.spongepowered.api.world.server.ServerWorld; -import org.spongepowered.api.world.server.WorldManager; - -/** - * Argument for retrieving {@link ServerWorld ServerWorlds} from the {@link WorldManager} by their {@link ResourceKey}. - * - * @param sender type - */ -public final class WorldArgument extends CommandArgument { - - private WorldArgument( - final boolean required, - final @NonNull String name, - final @NonNull String defaultValue, - final @Nullable BiFunction, String, List> suggestionsProvider, - final @NonNull ArgumentDescription defaultDescription - ) { - super( - required, - name, - new Parser<>(), - defaultValue, - ServerWorld.class, - suggestionsProvider, - defaultDescription - ); - } - - /** - * Create a new required {@link WorldArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link WorldArgument} - */ - public static @NonNull WorldArgument of(final @NonNull String name) { - return WorldArgument.builder(name).build(); - } - - /** - * Create a new optional {@link WorldArgument}. - * - * @param name argument name - * @param sender type - * @return a new {@link WorldArgument} - */ - public static @NonNull WorldArgument optional(final @NonNull String name) { - return WorldArgument.builder(name).asOptional().build(); - } - - /** - * Create a new optional {@link WorldArgument} with the specified default value. - * - * @param name argument name - * @param defaultValue default value - * @param sender type - * @return a new {@link WorldArgument} - */ - public static @NonNull WorldArgument optional(final @NonNull String name, final @NonNull ResourceKey defaultValue) { - return WorldArgument.builder(name).asOptionalWithDefault(defaultValue).build(); - } - - /** - * Create a new {@link Builder}. - * - * @param name argument name - * @param sender type - * @return a new {@link Builder} - */ - public static @NonNull Builder builder(final @NonNull String name) { - return new Builder<>(name); - } - - /** - * Parser for {@link ServerWorld ServerWorlds} in the {@link WorldManager}. - * - * @param sender type - */ - public static final class Parser implements NodeSupplyingArgumentParser { - - private static final DynamicCommandExceptionType ERROR_INVALID_VALUE; - - static { - try { - // ERROR_INVALID_VALUE (todo: use accessor) - final Field errorInvalidValueField = Arrays.stream(DimensionArgument.class.getDeclaredFields()) - .filter(f -> f.getType().equals(DynamicCommandExceptionType.class)) - .findFirst() - .orElseThrow(IllegalStateException::new); - errorInvalidValueField.setAccessible(true); - ERROR_INVALID_VALUE = (DynamicCommandExceptionType) errorInvalidValueField.get(null); - } catch (final Exception ex) { - throw new RuntimeException("Couldn't access ERROR_INVALID_VALUE command exception type.", ex); - } - } - - @Override - public @NonNull ArgumentParseResult<@NonNull ServerWorld> parse( - @NonNull final CommandContext<@NonNull C> commandContext, - @NonNull final Queue<@NonNull String> inputQueue - ) { - final String input = inputQueue.peek(); - final ResourceKey key = ResourceKeyUtil.resourceKey(input); - if (key == null) { - return ResourceKeyUtil.invalidResourceKey(); - } - final Optional entry = Sponge.server().worldManager().world(key); - if (entry.isPresent()) { - inputQueue.remove(); - return ArgumentParseResult.success(entry.get()); - } - return ArgumentParseResult.failure(ERROR_INVALID_VALUE.create(key)); - } - - @Override - public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input - ) { - return Sponge.server().worldManager().worlds().stream().flatMap(world -> { - if (!input.isEmpty() && world.key().namespace().equals(ResourceKey.MINECRAFT_NAMESPACE)) { - return Stream.of(world.key().value(), world.key().asString()); - } - return Stream.of(world.key().asString()); - }).collect(Collectors.toList()); - } - - @Override - public CommandTreeNode.@NonNull Argument> node() { - return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode().customCompletions(); - } - - } - - /** - * Builder for {@link WorldArgument}. - * - * @param sender type - */ - public static final class Builder extends TypedBuilder> { - - Builder(final @NonNull String name) { - super(ServerWorld.class, name); - } - - @Override - public @NonNull WorldArgument build() { - return new WorldArgument<>( - this.isRequired(), - this.getName(), - this.getDefaultValue(), - this.getSuggestionsProvider(), - this.getDefaultDescription() - ); - } - - /** - * Sets the command argument to be optional, with the specified default value. - * - * @param defaultValue default value - * @return this builder - * @see CommandArgument.Builder#asOptionalWithDefault(String) - */ - public @NonNull Builder asOptionalWithDefault(final @NonNull ResourceKey defaultValue) { - return this.asOptionalWithDefault(defaultValue.asString()); - } - - } - -} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockInputParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockInputParser.java new file mode 100644 index 00000000..c61231d1 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockInputParser.java @@ -0,0 +1,151 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.data.BlockInput; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.arguments.blocks.BlockStateArgument; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.world.BlockChangeFlag; +import org.spongepowered.api.world.BlockChangeFlags; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.common.data.persistence.NBTTranslator; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.common.world.SpongeBlockChangeFlag; + +/** + * An argument for parsing {@link BlockInput} from a {@link BlockState} + * and optional extra NBT data. + * + *

Example input strings:

+ *
    + *
  • {@code stone}
  • + *
  • {@code minecraft:stone}
  • + *
  • {@code andesite_stairs[waterlogged=true,facing=east]}
  • + *
+ * + * @param sender type + */ +public final class BlockInputParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor blockInputParser() { + return ParserDescriptor.of(new BlockInputParser<>(), BlockInput.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser(BlockStateArgument.block()) + .flatMapSuccess((ctx, blockInput) -> ArgumentParseResult.successFuture(new BlockInputImpl(blockInput))); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.BLOCK_STATE.get().createNode(); + } + + private static final class BlockInputImpl implements BlockInput { + + // todo: use accessor + private static final Field COMPOUND_TAG_FIELD = + Arrays.stream(net.minecraft.commands.arguments.blocks.BlockInput.class.getDeclaredFields()) + .filter(f -> f.getType().equals(CompoundTag.class)) + .findFirst() + .orElseThrow(IllegalStateException::new); + + static { + COMPOUND_TAG_FIELD.setAccessible(true); + } + + private final net.minecraft.commands.arguments.blocks.BlockInput blockInput; + private final @Nullable DataContainer extraData; + + BlockInputImpl(final net.minecraft.commands.arguments.blocks.@NonNull BlockInput blockInput) { + this.blockInput = blockInput; + try { + final CompoundTag tag = (CompoundTag) COMPOUND_TAG_FIELD.get(blockInput); + this.extraData = tag == null ? null : NBTTranslator.INSTANCE.translate(tag); + } catch (final IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public @NonNull BlockState blockState() { + return (BlockState) this.blockInput.getState(); + } + + @Override + public @Nullable DataContainer extraData() { + return this.extraData; + } + + @Override + public boolean place(final @NonNull ServerLocation location) { + return this.place(location, BlockChangeFlags.DEFAULT_PLACEMENT); + } + + @Override + public boolean place(final @NonNull ServerLocation location, final @NonNull BlockChangeFlag flag) { + return this.blockInput.place( + (ServerLevel) location.world(), + VecHelper.toBlockPos(location.position()), + ((SpongeBlockChangeFlag) flag).getRawFlag() + ); + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockPredicateParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockPredicateParser.java new file mode 100644 index 00000000..cb9250f2 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/BlockPredicateParser.java @@ -0,0 +1,134 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.BlockPredicate; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.common.util.VecHelper; + +/** + * An argument for parsing {@link BlockPredicate BlockPredicates}. + * + * @param sender type + */ +public final class BlockPredicateParser implements ArgumentParser.FutureArgumentParser, NodeSource, SuggestionProvider { + + public static ParserDescriptor blockPredicateParser() { + return ParserDescriptor.of(new BlockPredicateParser<>(), BlockPredicate.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser( + net.minecraft.commands.arguments.blocks.BlockPredicateArgument.blockPredicate() + ).flatMapSuccess((ctx, result) -> { + final CommandSourceStack commandSourceStack = + (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE); + try { + return ArgumentParseResult.successFuture( + new BlockPredicateImpl(result.create(commandSourceStack.getLevel().getTagManager())) + ); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failureFuture(ex); + } + }); + + @Override + public @NonNull CompletableFuture<@NonNull ArgumentParseResult> parseFuture( + final @NonNull CommandContext<@NonNull C> commandContext, + final @NonNull CommandInput commandInput + ) { + return this.mappedParser.parseFuture(commandContext, commandInput); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.BLOCK_PREDICATE.get().createNode(); + } + + private static final class BlockPredicateImpl implements BlockPredicate { + + private final Predicate predicate; + + BlockPredicateImpl(final @NonNull Predicate predicate) { + this.predicate = predicate; + } + + private boolean testImpl(final @NonNull ServerLocation location, final boolean loadChunks) { + return this.predicate.test(new BlockInWorld( + (ServerLevel) location.world(), + VecHelper.toBlockPos(location.position()), + loadChunks + )); + } + + @Override + public boolean test(final @NonNull ServerLocation location) { + return this.testImpl(location, false); + } + + @Override + public @NonNull BlockPredicate loadChunks() { + return new BlockPredicate() { + @Override + public @NonNull BlockPredicate loadChunks() { + return this; + } + + @Override + public boolean test(final @NonNull ServerLocation location) { + return BlockPredicateImpl.this.testImpl(location, true); + } + }; + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ComponentParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ComponentParser.java new file mode 100644 index 00000000..98fe06cd --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ComponentParser.java @@ -0,0 +1,80 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import java.util.concurrent.CompletableFuture; +import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.common.adventure.SpongeAdventure; + +/** + * An argument for parsing {@link Component Components} from json formatted text. + * + * @param sender type + */ +public final class ComponentParser implements ArgumentParser.FutureArgumentParser, NodeSource, SuggestionProvider { + + public static ParserDescriptor componentParser() { + return ParserDescriptor.of(new ComponentParser<>(), Component.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser( + net.minecraft.commands.arguments.ComponentArgument.textComponent() + ).flatMapSuccess((ctx, component) -> + ArgumentParseResult.successFuture(SpongeAdventure.asAdventure(component))); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.COMPONENT.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/DataContainerParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/DataContainerParser.java new file mode 100644 index 00000000..86befb5b --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/DataContainerParser.java @@ -0,0 +1,79 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.arguments.CompoundTagArgument; +import net.minecraft.nbt.CompoundTag; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.common.data.persistence.NBTTranslator; + +/** + * Argument for parsing {@link DataContainer DataContainers} from + * SNBT strings. + * + * @param sender type + */ +public final class DataContainerParser implements ArgumentParser.FutureArgumentParser, NodeSource, SuggestionProvider { + + public static ParserDescriptor dataContainerParser() { + return ParserDescriptor.of(new DataContainerParser<>(), DataContainer.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser(CompoundTagArgument.compoundTag()) + .flatMapSuccess((ctx, compoundTag) -> + ArgumentParseResult.successFuture(NBTTranslator.INSTANCE.translate(compoundTag))); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.NBT_COMPOUND_TAG.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileCollectionParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileCollectionParser.java new file mode 100644 index 00000000..1e86d244 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileCollectionParser.java @@ -0,0 +1,133 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.GameProfileCollection; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.GameProfileArgument; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.profile.GameProfile; +import org.spongepowered.common.profile.SpongeGameProfile; + +/** + * Argument for parsing a {@link Collection} of {@link GameProfile GameProfiles} from a + * {@link Selector}. A successfully parsed result will contain at least one element. + * + * @param sender type + */ +public final class GameProfileCollectionParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor gameProfileCollectionParser() { + return ParserDescriptor.of(new GameProfileCollectionParser<>(), GameProfileCollection.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser( + net.minecraft.commands.arguments.GameProfileArgument.gameProfile() + ).flatMapSuccess((ctx, argumentResult) -> { + final Collection profiles; + try { + profiles = argumentResult.getNames( + (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) + ); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failureFuture(ex); + } + final List result = profiles.stream() + .map(SpongeGameProfile::of).collect(Collectors.toList()); + return ArgumentParseResult.successFuture(new GameProfileCollectionImpl(Collections.unmodifiableCollection(result))); + }); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.GAME_PROFILE.get().createNode(); + } + + + @DefaultQualifier(NonNull.class) + private static final class GameProfileCollectionImpl extends AbstractCollection + implements GameProfileCollection { + + private final Collection backing; + + private GameProfileCollectionImpl(final Collection backing) { + this.backing = backing; + } + + @Override + public int size() { + return this.backing.size(); + } + + @Override + public Iterator iterator() { + return this.backing.iterator(); + } + + @Override + public boolean add(final GameProfile gameProfile) { + return this.backing.add(gameProfile); + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileParser.java new file mode 100644 index 00000000..51868453 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/GameProfileParser.java @@ -0,0 +1,118 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.exceptions.parsing.ParserException; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCaptionKeys; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.profile.GameProfile; +import org.spongepowered.common.profile.SpongeGameProfile; + +/** + * Argument for parsing a single {@link GameProfile} from a {@link Selector}. + * + * @param sender type + */ +public final class GameProfileParser implements ArgumentParser.FutureArgumentParser, NodeSource, SuggestionProvider { + + public static ParserDescriptor gameProfileParser() { + return ParserDescriptor.of(new GameProfileParser<>(), GameProfile.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser( + net.minecraft.commands.arguments.GameProfileArgument.gameProfile() + ).flatMapSuccess((ctx, argumentResult) -> { + final Collection profiles; + try { + profiles = argumentResult.getNames( + (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) + ); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failureFuture(ex); + } + if (profiles.size() > 1) { + return ArgumentParseResult.failureFuture(new TooManyGameProfilesSelectedException(ctx)); + } + final GameProfile profile = SpongeGameProfile.of(profiles.iterator().next()); + return ArgumentParseResult.successFuture(profile); + }); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.GAME_PROFILE.get().createNode(); + } + + + /** + * Exception thrown when too many game profiles are selected. + */ + private static final class TooManyGameProfilesSelectedException extends ParserException { + + private static final long serialVersionUID = -2931411139985042222L; + + TooManyGameProfilesSelectedException(final @NonNull CommandContext context) { + super( + GameProfileParser.class, + context, + SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_GAME_PROFILE_TOO_MANY_SELECTED + ); + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ItemStackPredicateParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ItemStackPredicateParser.java new file mode 100644 index 00000000..b91eac4d --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ItemStackPredicateParser.java @@ -0,0 +1,130 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.ItemStackPredicate; +import com.mojang.brigadier.context.StringRange; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.item.ItemPredicateArgument; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.item.inventory.ItemStack; + +/** + * An argument for parsing {@link ItemStackPredicate ItemStackPredicates}. + * + * @param sender type + */ +public final class ItemStackPredicateParser implements ArgumentParser.FutureArgumentParser, NodeSource, SuggestionProvider { + + public static ParserDescriptor itemStackPredicateParser() { + return ParserDescriptor.of(new ItemStackPredicateParser<>(), ItemStackPredicate.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser( + ItemPredicateArgument.itemPredicate() + ).flatMapSuccess((ctx, result) -> { + final CommandSourceStack commandSourceStack = + (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE); + try { + final com.mojang.brigadier.context.CommandContext dummyContext = + createDummyContext(ctx, commandSourceStack); + return ArgumentParseResult.successFuture(new ItemStackPredicateImpl(result.create(dummyContext))); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failureFuture(ex); + } + }); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.ITEM_PREDICATE.get().createNode(); + } + + private static final class ItemStackPredicateImpl implements ItemStackPredicate { + + private final Predicate predicate; + + ItemStackPredicateImpl(final @NonNull Predicate predicate) { + this.predicate = predicate; + } + + @SuppressWarnings("ConstantConditions") + @Override + public boolean test(final @NonNull ItemStack itemStack) { + return this.predicate.test((net.minecraft.world.item.ItemStack) (Object) itemStack); + } + + } + + private static com.mojang.brigadier.context.@NonNull CommandContext createDummyContext( + final @NonNull CommandContext ctx, + final @NonNull CommandSourceStack commandSourceStack + ) { + return new com.mojang.brigadier.context.CommandContext<>( + commandSourceStack, + ctx.rawInput().input(), + Collections.emptyMap(), + null, + null, + Collections.emptyList(), + StringRange.at(0), + null, + null, + false + ); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultipleEntitySelectorParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultipleEntitySelectorParser.java new file mode 100644 index 00000000..c4cae07e --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultipleEntitySelectorParser.java @@ -0,0 +1,134 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.MultipleEntitySelector; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.selector.EntitySelector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.entity.Entity; + +/** + * Argument for selecting one or more {@link Entity Entities} using a {@link Selector}. + * + * @param sender type + */ +public final class MultipleEntitySelectorParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor multipleEntitySelectorParser() { + return ParserDescriptor.of(new MultipleEntitySelectorParser<>(), MultipleEntitySelector.class); + } + + + private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.entities()); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final CommandInput originalInput = inputQueue.copy(); + return this.nativeParser.parseFuture(commandContext, inputQueue).thenApply(result -> { + if (result.failure().isPresent()) { + return ArgumentParseResult.failure(result.failure().get()); + } + final String consumedInput = originalInput.difference(inputQueue); + final EntitySelector parsed = result.parsedValue().get(); + final List entities; + try { + entities = parsed.findEntities( + ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) + ).stream().map(e -> (Entity) e).collect(Collectors.toList()); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } + return ArgumentParseResult.success(new MultipleEntitySelectorImpl((Selector) parsed, consumedInput, entities)); + }); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.nativeParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.ENTITY.get().createNode(); + } + + private static final class MultipleEntitySelectorImpl implements MultipleEntitySelector { + + private final Selector selector; + private final String inputString; + private final Collection result; + + private MultipleEntitySelectorImpl( + final Selector selector, + final String inputString, + final Collection result + ) { + this.selector = selector; + this.inputString = inputString; + this.result = result; + } + + @Override + public @NonNull Selector selector() { + return this.selector; + } + + @Override + public @NonNull String inputString() { + return this.inputString; + } + + @Override + public @NonNull Collection get() { + return this.result; + } + + } +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultiplePlayerSelectorParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultiplePlayerSelectorParser.java new file mode 100644 index 00000000..88e8f9b9 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/MultiplePlayerSelectorParser.java @@ -0,0 +1,135 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.MultiplePlayerSelector; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.selector.EntitySelector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; + +/** + * Argument for selecting one or more {@link Player Players} using a {@link Selector}. + * + * @param sender type + */ +public final class MultiplePlayerSelectorParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor multiplePlayerSelectorParser() { + return ParserDescriptor.of(new MultiplePlayerSelectorParser<>(), MultiplePlayerSelector.class); + } + + private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.players()); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final CommandInput originalInput = inputQueue.copy(); + return this.nativeParser.parseFuture(commandContext, inputQueue).thenApply(result -> { + if (result.failure().isPresent()) { + return ArgumentParseResult.failure(result.failure().get()); + } + final String consumedInput = originalInput.difference(inputQueue); + final EntitySelector parsed = result.parsedValue().get(); + final List players; + try { + players = parsed.findPlayers( + ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) + ).stream().map(p -> (ServerPlayer) p).collect(Collectors.toList()); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } + return ArgumentParseResult.success(new MultiplePlayerSelectorImpl((Selector) parsed, consumedInput, players)); + }); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.nativeParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.ENTITY.get().createNode().playersOnly(); + } + + private static final class MultiplePlayerSelectorImpl implements MultiplePlayerSelector { + + private final Selector selector; + private final String inputString; + private final Collection result; + + private MultiplePlayerSelectorImpl( + final Selector selector, + final String inputString, + final Collection result + ) { + this.selector = selector; + this.inputString = inputString; + this.result = result; + } + + @Override + public @NonNull Selector selector() { + return this.selector; + } + + @Override + public @NonNull String inputString() { + return this.inputString; + } + + @Override + public @NonNull Collection get() { + return this.result; + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/NamedTextColorParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/NamedTextColorParser.java new file mode 100644 index 00000000..71bc0b98 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/NamedTextColorParser.java @@ -0,0 +1,78 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.BlockingSuggestionProvider; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import java.util.ArrayList; +import java.util.Locale; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minecraft.commands.arguments.ColorArgument; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; + +/** + * An argument for parsing {@link NamedTextColor NamedTextColors}. + * + * @param sender type + */ +public final class NamedTextColorParser implements NodeSource, ArgumentParser, BlockingSuggestionProvider.Strings { + + public static ParserDescriptor namedTextColorParser() { + return ParserDescriptor.of(new NamedTextColorParser<>(), NamedTextColor.class); + } + + @Override + public @NonNull ArgumentParseResult<@NonNull NamedTextColor> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final String input = inputQueue.readString().toLowerCase(Locale.ROOT); + final NamedTextColor color = NamedTextColor.NAMES.value(input); + if (color != null) { + return ArgumentParseResult.success(color); + } + return ArgumentParseResult.failure(ColorArgument.ERROR_INVALID_VALUE.create(input)); + } + + @Override + public @NonNull Iterable<@NonNull String> stringSuggestions( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return new ArrayList<>(NamedTextColor.NAMES.keys()); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.COLOR.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/OperatorParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/OperatorParser.java new file mode 100644 index 00000000..efe4049e --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/OperatorParser.java @@ -0,0 +1,99 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.BlockingSuggestionProvider; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.stream.Collectors; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.parameter.managed.operator.Operator; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.registry.RegistryTypes; + +/** + * An argument for parsing {@link Operator Operators}. + * + * @param sender type + */ +public final class OperatorParser implements NodeSource, ArgumentParser, BlockingSuggestionProvider.Strings { + + public static ParserDescriptor operatorParser() { + return ParserDescriptor.of(new OperatorParser<>(), Operator.class); + } + + private static final SimpleCommandExceptionType ERROR_INVALID_OPERATION; + + static { + try { + // todo: fix in a better way + final Class spongeAccessor = + Class.forName("org.spongepowered.common.accessor.commands.arguments.OperationArgumentAccessor"); + final Method get = spongeAccessor.getDeclaredMethod("accessor$ERROR_INVALID_OPERATION"); + get.setAccessible(true); + ERROR_INVALID_OPERATION = (SimpleCommandExceptionType) get.invoke(null); + } catch (final ReflectiveOperationException ex) { + throw new RuntimeException("Couldn't access ERROR_INVALID_OPERATION command exception type.", ex); + } + } + + @Override + public @NonNull ArgumentParseResult<@NonNull Operator> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final String input = inputQueue.readString(); + final Optional operator = RegistryTypes.OPERATOR.get().stream() + .filter(op -> op.asString().equals(input)) + .findFirst(); + if (!operator.isPresent()) { + return ArgumentParseResult.failure(ERROR_INVALID_OPERATION.create()); + } + return ArgumentParseResult.success(operator.get()); + } + + @Override + public @NonNull Iterable<@NonNull String> stringSuggestions( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return RegistryTypes.OPERATOR.get().stream() + .map(Operator::asString) + .collect(Collectors.toList()); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.OPERATION.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ProtoItemStackParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ProtoItemStackParser.java new file mode 100644 index 00000000..3fa2ff03 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ProtoItemStackParser.java @@ -0,0 +1,158 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.data.ProtoItemStack; +import cloud.commandframework.sponge.exception.ComponentMessageRuntimeException; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import net.kyori.adventure.util.ComponentMessageThrowable; +import net.minecraft.commands.arguments.item.ItemArgument; +import net.minecraft.commands.arguments.item.ItemInput; +import net.minecraft.nbt.CompoundTag; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.ItemStackSnapshot; +import org.spongepowered.common.data.persistence.NBTTranslator; + +/** + * An argument for parsing {@link ProtoItemStack ProtoItemStacks} from an {@link ItemType} identifier + * and optional NBT data. The stack size of the resulting snapshot will always be {@code 1}. + * + *

Example input strings:

+ *
    + *
  • {@code apple}
  • + *
  • {@code minecraft:apple}
  • + *
  • {@code diamond_sword{Enchantments:[{id:sharpness,lvl:5}]}}
  • + *
+ * + * @param sender type + */ +public final class ProtoItemStackParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor protoItemStackParser() { + return ParserDescriptor.of(new ProtoItemStackParser<>(), ProtoItemStack.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser(ItemArgument.item()) + .flatMapSuccess((ctx, itemInput) -> ArgumentParseResult.successFuture(new ProtoItemStackImpl(itemInput))); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.ITEM_STACK.get().createNode(); + } + + private static final class ProtoItemStackImpl implements ProtoItemStack { + + // todo: use accessor + private static final Field COMPOUND_TAG_FIELD = + Arrays.stream(ItemInput.class.getDeclaredFields()) + .filter(f -> f.getType().equals(CompoundTag.class)) + .findFirst() + .orElseThrow(IllegalStateException::new); + + static { + COMPOUND_TAG_FIELD.setAccessible(true); + } + + private final ItemInput itemInput; + private final @Nullable DataContainer extraData; + + ProtoItemStackImpl(final @NonNull ItemInput itemInput) { + this.itemInput = itemInput; + try { + final CompoundTag tag = (CompoundTag) COMPOUND_TAG_FIELD.get(itemInput); + this.extraData = tag == null ? null : NBTTranslator.INSTANCE.translate(tag); + } catch (final IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public @NonNull ItemType itemType() { + return (ItemType) this.itemInput.getItem(); + } + + @Override + public @Nullable DataContainer extraData() { + return this.extraData; + } + + @SuppressWarnings("ConstantConditions") + @Override + public @NonNull ItemStack createItemStack( + final int stackSize, + final boolean respectMaximumStackSize + ) throws ComponentMessageRuntimeException { + try { + return (ItemStack) (Object) this.itemInput.createItemStack(stackSize, respectMaximumStackSize); + } catch (final CommandSyntaxException ex) { + throw new ComponentMessageRuntimeException(ComponentMessageThrowable.getMessage(ex), ex); + } + } + + @Override + public @NonNull ItemStackSnapshot createItemStackSnapshot( + final int stackSize, + final boolean respectMaximumStackSize + ) throws ComponentMessageRuntimeException { + return this.createItemStack(stackSize, respectMaximumStackSize).createSnapshot(); + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/RegistryEntryParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/RegistryEntryParser.java new file mode 100644 index 00000000..15f3534f --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/RegistryEntryParser.java @@ -0,0 +1,258 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.BlockingSuggestionProvider; +import cloud.commandframework.captions.CaptionVariable; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.exceptions.parsing.ParserException; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCaptionKeys; +import io.leangen.geantyref.TypeToken; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.command.registrar.tree.CommandCompletionProviders; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.registry.DefaultedRegistryType; +import org.spongepowered.api.registry.Registry; +import org.spongepowered.api.registry.RegistryEntry; +import org.spongepowered.api.registry.RegistryHolder; +import org.spongepowered.api.registry.RegistryType; +import org.spongepowered.api.registry.RegistryTypes; + +/** + * An argument for retrieving values from any of Sponge's {@link Registry Registries}. + * + * @param sender type + * @param value type + */ +public final class RegistryEntryParser implements NodeSource, ArgumentParser.FutureArgumentParser, BlockingSuggestionProvider.Strings { + + // Start DefaultedRegistryType methods + + /** + * Create a new required {@link RegistryEntryParser} for a {@link DefaultedRegistryType}. + * + * @param valueType value type + * @param registryType registry type + * @param sender type + * @param value type + * @return a new {@link RegistryEntryParser} + */ + public static @NonNull ParserDescriptor registryEntryParser( + final @NonNull TypeToken valueType, + final @NonNull DefaultedRegistryType registryType + ) { + return ParserDescriptor.of(new RegistryEntryParser<>(registryType), valueType); + } + + /** + * Create a new required {@link RegistryEntryParser} for a {@link DefaultedRegistryType}. + * + * @param valueType value type + * @param registryType registry type + * @param sender type + * @param value type + * @return a new {@link RegistryEntryParser} + */ + public static @NonNull ParserDescriptor registryEntryParser( + final @NonNull Class valueType, + final @NonNull DefaultedRegistryType registryType + ) { + return ParserDescriptor.of(new RegistryEntryParser<>(registryType), valueType); + } + + // End DefaultedRegistryType methods + + // Start RegistryType methods + + /** + * Create a new required {@link RegistryEntryParser} for a {@link RegistryType} + * using the specified {@link RegistryHolder} function. + * + *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, + * it is suggested to instead use {@link #registryEntryParser(TypeToken, DefaultedRegistryType)}.

+ * + * @param sender type + * @param value type + * @param valueType value type + * @param registryType registry type + * @param holderSupplier registry holder function + * @return a new {@link RegistryEntryParser} + */ + public static @NonNull ParserDescriptor registryEntryParser( + final @NonNull Class valueType, + final @NonNull RegistryType registryType, + final @NonNull Function, RegistryHolder> holderSupplier + ) { + return ParserDescriptor.of(new RegistryEntryParser<>(holderSupplier, registryType), valueType); + } + + /** + * Create a new required {@link RegistryEntryParser} for a {@link RegistryType} + * using the specified {@link RegistryHolder} function. + * + *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, + * it is suggested to instead use {@link #registryEntryParser(TypeToken, DefaultedRegistryType)}.

+ * + * @param sender type + * @param value type + * @param valueType value type + * @param registryType registry type + * @param holderSupplier registry holder function + * @return a new {@link RegistryEntryParser} + */ + public static @NonNull ParserDescriptor registryEntryParser( + final @NonNull TypeToken valueType, + final @NonNull RegistryType registryType, + final @NonNull Function, RegistryHolder> holderSupplier + ) { + return ParserDescriptor.of(new RegistryEntryParser<>(holderSupplier, registryType), valueType); + } + + // End RegistryType methods + + private static final ArgumentParser RESOURCE_KEY_PARSER = new ResourceKeyParser<>(); + + private final Function, RegistryHolder> holderSupplier; + private final RegistryType registryType; + + /** + * Create a new {@link RegistryEntryParser} using the specified {@link RegistryHolder} function. + * + *

For {@link RegistryType RegistryTypes} which are {@link DefaultedRegistryType DefaultedRegistryTypes}, + * it is suggested to instead use {@link #RegistryEntryParser(DefaultedRegistryType)}.

+ * + * @param holderSupplier registry holder function + * @param registryType registry type + */ + public RegistryEntryParser( + final @NonNull Function, RegistryHolder> holderSupplier, + final @NonNull RegistryType registryType + ) { + this.holderSupplier = holderSupplier; + this.registryType = registryType; + } + + /** + * Create a new {@link RegistryEntryParser}. + * + * @param registryType defaulted registry type + */ + public RegistryEntryParser(final @NonNull DefaultedRegistryType registryType) { + this(ctx -> registryType.defaultHolder().get(), registryType); + } + + private Registry registry(final @NonNull CommandContext commandContext) { + return this.holderSupplier.apply(commandContext).registry(this.registryType); + } + + @SuppressWarnings("unchecked") + @Override + public @NonNull CompletableFuture<@NonNull ArgumentParseResult<@NonNull V>> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return ((ArgumentParser) RESOURCE_KEY_PARSER).parseFuture(commandContext, inputQueue).thenApply(keyResult -> { + if (keyResult.failure().isPresent()) { + return ArgumentParseResult.failure(keyResult.failure().get()); + } + final Optional> entry = this.registry(commandContext).findEntry(keyResult.parsedValue().get()); + if (entry.isPresent()) { + return ArgumentParseResult.success(entry.get().value()); + } + return ArgumentParseResult.failure(new NoSuchEntryException(commandContext, keyResult.parsedValue().get(), this.registryType)); + }); + } + + @Override + public @NonNull List<@NonNull String> stringSuggestions( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return this.registry(commandContext).streamEntries().flatMap(entry -> { + if (!input.isEmpty() && entry.key().namespace().equals(ResourceKey.MINECRAFT_NAMESPACE)) { + return Stream.of(entry.key().value(), entry.key().asString()); + } + return Stream.of(entry.key().asString()); + }).collect(Collectors.toList()); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + if (this.registryType.equals(RegistryTypes.SOUND_TYPE)) { + return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode() + .completions(CommandCompletionProviders.AVAILABLE_SOUNDS); + } else if (this.registryType.equals(RegistryTypes.BIOME)) { + return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode() + .completions(CommandCompletionProviders.AVAILABLE_BIOMES); + } else if (this.registryType.equals(RegistryTypes.ENTITY_TYPE)) { + return CommandTreeNodeTypes.ENTITY_SUMMON.get().createNode() + .completions(CommandCompletionProviders.SUMMONABLE_ENTITIES); + } else if (this.registryType.equals(RegistryTypes.ENCHANTMENT_TYPE)) { + return CommandTreeNodeTypes.ITEM_ENCHANTMENT.get().createNode(); + } else if (this.registryType.equals(RegistryTypes.POTION_EFFECT_TYPE)) { + return CommandTreeNodeTypes.MOB_EFFECT.get().createNode(); + } else if (this.registryType.equals(RegistryTypes.WORLD_TYPE)) { + return CommandTreeNodeTypes.DIMENSION.get().createNode() + .customCompletions(); // Sponge adds custom types (?) + } + return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode().customCompletions(); + } + + /** + * An exception thrown when there is no entry for the provided {@link ResourceKey} in the resolved registry. + */ + private static final class NoSuchEntryException extends ParserException { + + private static final long serialVersionUID = 4472876671109079272L; + + NoSuchEntryException( + final CommandContext context, + final ResourceKey key, + final RegistryType registryType + ) { + super( + RegistryEntryParser.class, + context, + SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY, + CaptionVariable.of("id", key.asString()), + CaptionVariable.of("registry", registryType.location().asString()) + ); + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyParser.java new file mode 100644 index 00000000..974566cf --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyParser.java @@ -0,0 +1,66 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; + +/** + * Argument for parsing {@link ResourceKey ResourceKeys}. + * + * @param sender type + */ +public final class ResourceKeyParser implements NodeSource, ArgumentParser { + + public static ParserDescriptor resourceKeyParser() { + return ParserDescriptor.of(new ResourceKeyParser<>(), ResourceKey.class); + } + + @Override + public @NonNull ArgumentParseResult<@NonNull ResourceKey> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final String input = inputQueue.readString(); + final ResourceKey key = ResourceKeyUtil.resourceKey(input); + if (key == null) { + return ResourceKeyUtil.invalidResourceKey(); + } + return ArgumentParseResult.success(key); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyUtil.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyUtil.java similarity index 98% rename from cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyUtil.java rename to cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyUtil.java index c351ddac..444c725c 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/ResourceKeyUtil.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/ResourceKeyUtil.java @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // -package cloud.commandframework.sponge.argument; +package cloud.commandframework.sponge.parser; import cloud.commandframework.arguments.parser.ArgumentParseResult; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SingleEntitySelectorParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SingleEntitySelectorParser.java new file mode 100644 index 00000000..75ce31e0 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SingleEntitySelectorParser.java @@ -0,0 +1,131 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.SingleEntitySelector; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.selector.EntitySelector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.entity.Entity; + +/** + * Argument for selecting a single {@link Entity} using a {@link Selector}. + * + * @param sender type + */ +public final class SingleEntitySelectorParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor singleEntitySelectorParser() { + return ParserDescriptor.of(new SingleEntitySelectorParser<>(), SingleEntitySelector.class); + } + + private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.entity()); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final CommandInput originalInput = inputQueue.copy(); + return this.nativeParser.parseFuture(commandContext, inputQueue).thenApply(result -> { + if (result.failure().isPresent()) { + return ArgumentParseResult.failure(result.failure().get()); + } + final String consumedInput = originalInput.difference(inputQueue); + final EntitySelector parsed = result.parsedValue().get(); + final Entity entity; + try { + entity = (Entity) parsed.findSingleEntity( + ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) + ); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } + return ArgumentParseResult.success(new SingleEntitySelectorImpl((Selector) parsed, consumedInput, entity)); + }); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.nativeParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.ENTITY.get().createNode().single(); + } + + private static final class SingleEntitySelectorImpl implements SingleEntitySelector { + + private final Selector selector; + private final String inputString; + private final Entity result; + + private SingleEntitySelectorImpl( + final Selector selector, + final String inputString, + final Entity result + ) { + this.selector = selector; + this.inputString = inputString; + this.result = result; + } + + @Override + public @NonNull Selector selector() { + return this.selector; + } + + @Override + public @NonNull String inputString() { + return this.inputString; + } + + @Override + public @NonNull Entity getSingle() { + return this.result; + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SinglePlayerSelectorParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SinglePlayerSelectorParser.java new file mode 100644 index 00000000..b466f08e --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/SinglePlayerSelectorParser.java @@ -0,0 +1,134 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import cloud.commandframework.sponge.data.SinglePlayerSelector; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.selector.EntitySelector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; + +/** + * Argument for selecting a single {@link Player} using a {@link Selector}. + * + * @param sender type + */ +public final class SinglePlayerSelectorParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor singlePlayerSelectorParser() { + return ParserDescriptor.of(new SinglePlayerSelectorParser<>(), SinglePlayerSelector.class); + } + + private final ArgumentParser nativeParser = new WrappedBrigadierParser<>(EntityArgument.player()); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final CommandInput originalInput = inputQueue.copy(); + return this.nativeParser.parseFuture(commandContext, inputQueue).thenApply(result -> { + if (result.failure().isPresent()) { + return ArgumentParseResult.failure(result.failure().get()); + } + final String consumedInput = originalInput.difference(inputQueue); + final EntitySelector parsed = result.parsedValue().get(); + final ServerPlayer player; + try { + // todo: a more proper fix then setting permission level 2 + player = (ServerPlayer) parsed.findSinglePlayer( + ((CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE)).withPermission(2) + ); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } + return ArgumentParseResult.success(new SinglePlayerSelectorImpl((Selector) parsed, consumedInput, player)); + }); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.nativeParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.ENTITY.get().createNode().playersOnly().single(); + } + + + private static final class SinglePlayerSelectorImpl implements SinglePlayerSelector { + + private final Selector selector; + private final String inputString; + private final ServerPlayer result; + + private SinglePlayerSelectorImpl( + final Selector selector, + final String inputString, + final ServerPlayer result + ) { + this.selector = selector; + this.inputString = inputString; + this.result = result; + } + + @Override + public @NonNull Selector selector() { + return this.selector; + } + + @Override + public @NonNull String inputString() { + return this.inputString; + } + + @Override + public @NonNull ServerPlayer getSingle() { + return this.result; + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/UserParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/UserParser.java new file mode 100644 index 00000000..734f282b --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/UserParser.java @@ -0,0 +1,207 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.captions.Caption; +import cloud.commandframework.captions.CaptionVariable; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.exceptions.parsing.ParserException; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCaptionKeys; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.selector.EntitySelector; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.command.selector.Selector; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.profile.GameProfile; +import org.spongepowered.api.user.UserManager; + +/** + * Argument for parsing {@link User} {@link UUID UUIDs} in the {@link UserManager} from + * a {@link Selector}, last known username, or {@link UUID} string. + * + * @param sender type + */ +public final class UserParser implements NodeSource, ArgumentParser, SuggestionProvider { + + public static ParserDescriptor userParser() { + return ParserDescriptor.of(new UserParser<>(), UUID.class); + } + + private final ArgumentParser singlePlayerSelectorParser = + new WrappedBrigadierParser<>(EntityArgument.player()); + + @Override + public @NonNull ArgumentParseResult<@NonNull UUID> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final CommandInput inputCopy = inputQueue.copy(); + final String peek = inputQueue.readString(); + if (peek.startsWith("@")) { + return this.handleSelector(commandContext, inputCopy); + } + + try { + final Optional optionalUser = Sponge.server().gameProfileManager().cache().findByName(peek); + // valid username + if (optionalUser.isPresent()) { + return ArgumentParseResult.success(optionalUser.get().uniqueId()); + } + return ArgumentParseResult.failure(new UserNotFoundException( + commandContext, UserNotFoundException.Type.NAME, peek + )); + } catch (final IllegalArgumentException ex) { + // not a valid username + } + + try { + final UUID uuid = UUID.fromString(peek); + // valid uuid + if (Sponge.server().userManager().exists(uuid)) { + return ArgumentParseResult.success(uuid); + } + + return ArgumentParseResult.failure(new UserNotFoundException( + commandContext, UserNotFoundException.Type.UUID, peek + )); + } catch (final IllegalArgumentException ex) { + // not a valid uuid + } + + return ArgumentParseResult.failure(new UserNotFoundException( + commandContext, UserNotFoundException.Type.INVALID_INPUT, peek + )); + } + + private @NonNull ArgumentParseResult<@NonNull UUID> handleSelector( + final @NonNull CommandContext<@NonNull C> commandContext, + final @NonNull CommandInput inputQueue + ) { + final ArgumentParseResult result = this.singlePlayerSelectorParser.parse(commandContext, inputQueue); + if (result.failure().isPresent()) { + return ArgumentParseResult.failure(result.failure().get()); + } + final EntitySelector parsed = result.parsedValue().get(); + final ServerPlayer player; + try { + player = (ServerPlayer) parsed.findSinglePlayer( + (CommandSourceStack) commandContext.get(SpongeCommandContextKeys.COMMAND_CAUSE) + ); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } + return ArgumentParseResult.success(player.uniqueId()); + } + + @Override + public @NonNull CompletableFuture> suggestionsFuture( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return this.singlePlayerSelectorParser.suggestionProvider().suggestionsFuture(commandContext, input) + .thenApply(it -> { + final List suggestions = new ArrayList<>(); + it.forEach(suggestions::add); + final String peek = input.peekString(); + if (!peek.startsWith("@")) { + suggestions.addAll(Sponge.server().userManager().streamOfMatches(peek) + .filter(GameProfile::hasName) + .map(profile -> profile.name().orElse(null)) + .filter(Objects::nonNull) + .filter(name -> suggestions.stream().noneMatch(s -> s.suggestion().equals(name))) + .map(Suggestion::simple) + .collect(Collectors.toList())); + } + return suggestions; + }); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.GAME_PROFILE.get().createNode().customCompletions(); + } + + /** + * An exception thrown when a {@link User} cannot be found for the provided input. + */ + private static final class UserNotFoundException extends ParserException { + + private static final long serialVersionUID = -24501459406523175L; + + UserNotFoundException( + final CommandContext context, + final @NonNull Type type, + final @NonNull String input + ) { + super( + UserParser.class, + context, + type.caption, + type.variable(input) + ); + } + + private enum Type { + UUID("uuid", SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_UUID), + NAME("name", SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_CANNOT_FIND_USER_WITH_NAME), + INVALID_INPUT("input", SpongeCaptionKeys.ARGUMENT_PARSE_FAILURE_USER_INVALID_INPUT); + + private final String key; + private final Caption caption; + + Type(final @NonNull String key, final @NonNull Caption caption) { + this.key = key; + this.caption = caption; + } + + CaptionVariable variable(final @NonNull String input) { + return CaptionVariable.of(this.key, input); + } + } + + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2dParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2dParser.java new file mode 100644 index 00000000..edf0f3a6 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2dParser.java @@ -0,0 +1,104 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.coordinates.Coordinates; +import net.minecraft.commands.arguments.coordinates.Vec2Argument; +import net.minecraft.world.phys.Vec3; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.math.vector.Vector2d; + +/** + * Argument for parsing {@link Vector2d} from relative, absolute, or local coordinates. + * + *

Example input strings:

+ *
    + *
  • {@code ~ ~}
  • + *
  • {@code 0.1 -0.5}
  • + *
  • {@code ~1 ~-2}
  • + *
+ * + * @param sender type + */ +public final class Vector2dParser extends VectorParser { + + public static ParserDescriptor vector2dParser() { + return vector2dParser(false); + } + + public static ParserDescriptor vector2dParser(final boolean centerIntegers) { + return ParserDescriptor.of(new Vector2dParser<>(centerIntegers), Vector2d.class); + } + + private final ArgumentParser mappedParser; + + /** + * Create a new {@link Vector2dParser}. + * + * @param centerIntegers whether to center integers to x.5 + */ + public Vector2dParser(final boolean centerIntegers) { + super(centerIntegers); + this.mappedParser = new WrappedBrigadierParser(new Vec2Argument(centerIntegers)) + .flatMapSuccess((ctx, coordinates) -> { + final Vec3 position = coordinates.getPosition( + (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) + ); + return ArgumentParseResult.successFuture(new Vector2d(position.x, position.z)); + }); + } + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.VEC2.get().createNode(); + } +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2iParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2iParser.java new file mode 100644 index 00000000..375ccde6 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector2iParser.java @@ -0,0 +1,96 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.coordinates.ColumnPosArgument; +import net.minecraft.commands.arguments.coordinates.Coordinates; +import net.minecraft.core.BlockPos; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.math.vector.Vector2i; + +/** + * Argument for parsing {@link Vector2i} from relative, absolute, or local coordinates. + * + *

Example input strings:

+ *
    + *
  • {@code ~ ~}
  • + *
  • {@code 12 -7}
  • + *
  • {@code ^-1 ^0}
  • + *
  • {@code ~-1 ~5}
  • + *
  • {@code ^ ^}
  • + *
+ * + * @param sender type + */ +public final class Vector2iParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor vector2iParser() { + return ParserDescriptor.of(new Vector2iParser<>(), Vector2i.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser(ColumnPosArgument.columnPos()) + .flatMapSuccess((ctx, coordinates) -> { + final BlockPos pos = coordinates.getBlockPos( + (CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE) + ); + return ArgumentParseResult.successFuture(new Vector2i(pos.getX(), pos.getZ())); + }); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.COLUMN_POS.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3dParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3dParser.java new file mode 100644 index 00000000..7057c357 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3dParser.java @@ -0,0 +1,105 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.coordinates.Coordinates; +import net.minecraft.commands.arguments.coordinates.Vec3Argument; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.math.vector.Vector3d; + +/** + * Argument for parsing {@link Vector3d} from relative, absolute, or local coordinates. + * + *

Example input strings:

+ *
    + *
  • {@code ~ ~ ~}
  • + *
  • {@code 0.1 -0.5 .9}
  • + *
  • {@code ~1 ~-2 ~10}
  • + *
  • {@code ^1 ^ ^-5}
  • + *
+ * + * @param sender type + */ +public final class Vector3dParser extends VectorParser { + + public static ParserDescriptor vector3dParser() { + return vector3dParser(false); + } + + public static ParserDescriptor vector3dParser(final boolean centerIntegers) { + return ParserDescriptor.of(new Vector3dParser<>(centerIntegers), Vector3d.class); + } + + private final ArgumentParser mappedParser; + + /** + * Create a new {@link Vector3dParser}. + * + * @param centerIntegers whether to center integers to x.5 + */ + public Vector3dParser(final boolean centerIntegers) { + super(centerIntegers); + this.mappedParser = new WrappedBrigadierParser(new Vec3Argument(centerIntegers)) + .flatMapSuccess((ctx, coordinates) -> { + return ArgumentParseResult.successFuture(VecHelper.toVector3d( + coordinates.getPosition((CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE)) + )); + }); + } + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.VEC3.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3iParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3iParser.java new file mode 100644 index 00000000..c6f76920 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/Vector3iParser.java @@ -0,0 +1,94 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.Suggestion; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.brigadier.parser.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import cloud.commandframework.sponge.SpongeCommandContextKeys; +import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.coordinates.BlockPosArgument; +import net.minecraft.commands.arguments.coordinates.Coordinates; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.math.vector.Vector3i; + +/** + * Argument for parsing {@link Vector3i} from relative, absolute, or local coordinates. + * + *

Example input strings:

+ *
    + *
  • {@code ~ ~ ~}
  • + *
  • {@code 1 1 1}
  • + *
  • {@code ~0.5 ~-2 ~10}
  • + *
  • {@code ^1 ^ ^-5}
  • + *
+ * + * @param sender type + */ +public final class Vector3iParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + public static ParserDescriptor vector3iParser() { + return ParserDescriptor.of(new Vector3iParser<>(), Vector3i.class); + } + + private final ArgumentParser mappedParser = + new WrappedBrigadierParser(BlockPosArgument.blockPos()) + .flatMapSuccess((ctx, coordinates) -> { + return ArgumentParseResult.successFuture(VecHelper.toVector3i( + coordinates.getBlockPos((CommandSourceStack) ctx.get(SpongeCommandContextKeys.COMMAND_CAUSE)) + )); + }); + + @Override + public @NonNull CompletableFuture> parseFuture( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + return this.mappedParser.parseFuture(commandContext, inputQueue); + } + + @Override + public @NonNull CompletableFuture<@NonNull Iterable<@NonNull Suggestion>> suggestionsFuture( + final @NonNull CommandContext context, + final @NonNull CommandInput input + ) { + return this.mappedParser.suggestionProvider().suggestionsFuture(context, input); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.BLOCK_POS.get().createNode(); + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/package-info.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/VectorParser.java similarity index 52% rename from cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/package-info.java rename to cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/VectorParser.java index 6bcc6ca7..d1fb88e1 100644 --- a/cloud-sponge/src/main/java/cloud/commandframework/sponge/argument/package-info.java +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/VectorParser.java @@ -1,7 +1,7 @@ // // MIT License // -// Copyright (c) 2021 Alexander Söderberg & Contributors +// Copyright (c) 2022 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 @@ -21,7 +21,35 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // +package cloud.commandframework.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.suggestion.SuggestionProvider; +import cloud.commandframework.sponge.NodeSource; + /** - * Arguments for the Sponge 8 environment. + * Parent of {@link Vector3dParser} and {@link Vector2dParser} containing shared methods. + * + *

Not for extension by API users.

+ * + * @param sender type + * @param vector type */ -package cloud.commandframework.sponge.argument; +public abstract class VectorParser implements NodeSource, ArgumentParser.FutureArgumentParser, SuggestionProvider { + + private final boolean centerIntegers; + + protected VectorParser(final boolean centerIntegers) { + this.centerIntegers = centerIntegers; + } + + /** + * Get whether integers will be centered to x.5. Defaults to false. + * + * @return whether integers will be centered + */ + public final boolean centerIntegers() { + return this.centerIntegers; + } + +} diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/WorldParser.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/WorldParser.java new file mode 100644 index 00000000..f6fcf19d --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/WorldParser.java @@ -0,0 +1,112 @@ +// +// MIT License +// +// Copyright (c) 2022 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.sponge.parser; + +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.arguments.parser.ParserDescriptor; +import cloud.commandframework.arguments.suggestion.BlockingSuggestionProvider; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.context.CommandInput; +import cloud.commandframework.sponge.NodeSource; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import net.minecraft.commands.arguments.DimensionArgument; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.registrar.tree.CommandTreeNode; +import org.spongepowered.api.command.registrar.tree.CommandTreeNodeTypes; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.api.world.server.WorldManager; + +/** + * Argument for retrieving {@link ServerWorld ServerWorlds} from the {@link WorldManager} by their {@link ResourceKey}. + * + * @param sender type + */ +public final class WorldParser implements ArgumentParser, NodeSource, BlockingSuggestionProvider.Strings { + + public static ParserDescriptor worldParser() { + return ParserDescriptor.of(new WorldParser<>(), ServerWorld.class); + } + + private static final DynamicCommandExceptionType ERROR_INVALID_VALUE; + + static { + try { + // ERROR_INVALID_VALUE (todo: use accessor) + final Field errorInvalidValueField = Arrays.stream(DimensionArgument.class.getDeclaredFields()) + .filter(f -> f.getType().equals(DynamicCommandExceptionType.class)) + .findFirst() + .orElseThrow(IllegalStateException::new); + errorInvalidValueField.setAccessible(true); + ERROR_INVALID_VALUE = (DynamicCommandExceptionType) errorInvalidValueField.get(null); + } catch (final Exception ex) { + throw new RuntimeException("Couldn't access ERROR_INVALID_VALUE command exception type.", ex); + } + } + + @Override + public @NonNull ArgumentParseResult<@NonNull ServerWorld> parse( + @NonNull final CommandContext<@NonNull C> commandContext, + @NonNull final CommandInput inputQueue + ) { + final String input = inputQueue.readString(); + final ResourceKey key = ResourceKeyUtil.resourceKey(input); + if (key == null) { + return ResourceKeyUtil.invalidResourceKey(); + } + final Optional entry = Sponge.server().worldManager().world(key); + if (entry.isPresent()) { + return ArgumentParseResult.success(entry.get()); + } + return ArgumentParseResult.failure(ERROR_INVALID_VALUE.create(key)); + } + + @Override + public @NonNull List<@NonNull String> stringSuggestions( + final @NonNull CommandContext commandContext, + final @NonNull CommandInput input + ) { + return Sponge.server().worldManager().worlds().stream().flatMap(world -> { + if (!input.isEmpty() && world.key().namespace().equals(ResourceKey.MINECRAFT_NAMESPACE)) { + return Stream.of(world.key().value(), world.key().asString()); + } + return Stream.of(world.key().asString()); + }).collect(Collectors.toList()); + } + + @Override + public CommandTreeNode.@NonNull Argument> node() { + return CommandTreeNodeTypes.RESOURCE_LOCATION.get().createNode().customCompletions(); + } + +} + diff --git a/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/package-info.java b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/package-info.java new file mode 100644 index 00000000..637c61f3 --- /dev/null +++ b/cloud-sponge/src/main/java/cloud/commandframework/sponge/parser/package-info.java @@ -0,0 +1,4 @@ +/** + * Parsers for the Sponge 8 environment. + */ +package cloud.commandframework.sponge.parser; diff --git a/examples/example-sponge/src/main/java/cloud/commandframework/examples/sponge/CloudExamplePlugin.java b/examples/example-sponge/src/main/java/cloud/commandframework/examples/sponge/CloudExamplePlugin.java index 3d587ce4..f8502c35 100644 --- a/examples/example-sponge/src/main/java/cloud/commandframework/examples/sponge/CloudExamplePlugin.java +++ b/examples/example-sponge/src/main/java/cloud/commandframework/examples/sponge/CloudExamplePlugin.java @@ -23,27 +23,16 @@ // package cloud.commandframework.examples.sponge; -import cloud.commandframework.ArgumentDescription; import cloud.commandframework.Command; +import cloud.commandframework.Description; +import cloud.commandframework.arguments.DefaultValue; +import cloud.commandframework.arguments.standard.StringParser; import cloud.commandframework.context.CommandContext; import cloud.commandframework.execution.ExecutionCoordinator; import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler; +import cloud.commandframework.permission.PredicatePermission; import cloud.commandframework.sponge.CloudInjectionModule; import cloud.commandframework.sponge.SpongeCommandManager; -import cloud.commandframework.sponge.argument.BlockInputArgument; -import cloud.commandframework.sponge.argument.BlockPredicateArgument; -import cloud.commandframework.sponge.argument.DataContainerArgument; -import cloud.commandframework.sponge.argument.ItemStackPredicateArgument; -import cloud.commandframework.sponge.argument.MultipleEntitySelectorArgument; -import cloud.commandframework.sponge.argument.NamedTextColorArgument; -import cloud.commandframework.sponge.argument.OperatorArgument; -import cloud.commandframework.sponge.argument.ProtoItemStackArgument; -import cloud.commandframework.sponge.argument.RegistryEntryArgument; -import cloud.commandframework.sponge.argument.SinglePlayerSelectorArgument; -import cloud.commandframework.sponge.argument.UserArgument; -import cloud.commandframework.sponge.argument.Vector3dArgument; -import cloud.commandframework.sponge.argument.Vector3iArgument; -import cloud.commandframework.sponge.argument.WorldArgument; import cloud.commandframework.sponge.data.BlockInput; import cloud.commandframework.sponge.data.BlockPredicate; import cloud.commandframework.sponge.data.ItemStackPredicate; @@ -94,6 +83,24 @@ import org.spongepowered.math.vector.Vector3i; import org.spongepowered.plugin.builtin.jvm.Plugin; +import static cloud.commandframework.arguments.standard.DoubleParser.doubleParser; +import static cloud.commandframework.arguments.standard.IntegerParser.integerParser; +import static cloud.commandframework.arguments.standard.StringParser.greedyStringParser; +import static cloud.commandframework.arguments.standard.StringParser.stringParser; +import static cloud.commandframework.sponge.parser.BlockInputParser.blockInputParser; +import static cloud.commandframework.sponge.parser.BlockPredicateParser.blockPredicateParser; +import static cloud.commandframework.sponge.parser.DataContainerParser.dataContainerParser; +import static cloud.commandframework.sponge.parser.ItemStackPredicateParser.itemStackPredicateParser; +import static cloud.commandframework.sponge.parser.MultipleEntitySelectorParser.multipleEntitySelectorParser; +import static cloud.commandframework.sponge.parser.NamedTextColorParser.namedTextColorParser; +import static cloud.commandframework.sponge.parser.OperatorParser.operatorParser; +import static cloud.commandframework.sponge.parser.ProtoItemStackParser.protoItemStackParser; +import static cloud.commandframework.sponge.parser.RegistryEntryParser.registryEntryParser; +import static cloud.commandframework.sponge.parser.SinglePlayerSelectorParser.singlePlayerSelectorParser; +import static cloud.commandframework.sponge.parser.UserParser.userParser; +import static cloud.commandframework.sponge.parser.Vector3dParser.vector3dParser; +import static cloud.commandframework.sponge.parser.Vector3iParser.vector3iParser; +import static cloud.commandframework.sponge.parser.WorldParser.worldParser; import static net.kyori.adventure.text.Component.newline; import static net.kyori.adventure.text.Component.space; import static net.kyori.adventure.text.Component.text; @@ -109,11 +116,11 @@ public final class CloudExamplePlugin { private static final Component COMMAND_PREFIX = text() - .color(color(0x333333)) - .content("[") - .append(text("Cloud-Sponge", color(0xF7CF0D))) - .append(text(']')) - .build(); + .color(color(0x333333)) + .content("[") + .append(text("Cloud-Sponge", color(0xF7CF0D))) + .append(text(']')) + .build(); private final SpongeCommandManager commandManager; @@ -126,322 +133,318 @@ public final class CloudExamplePlugin { public CloudExamplePlugin(final @NonNull Injector injector) { // Create child injector with cloud module final Injector childInjector = injector.createChildInjector( - CloudInjectionModule.createNative(ExecutionCoordinator.simpleCoordinator()) + CloudInjectionModule.createNative(ExecutionCoordinator.simpleCoordinator()) ); // Get command manager instance - this.commandManager = childInjector.getInstance(Key.get(new TypeLiteral>() { - })); + this.commandManager = childInjector.getInstance(Key.get(new TypeLiteral>() {})); // Use Cloud's enhanced number suggestions this.commandManager.parserMapper().cloudNumberSuggestions(true); // Register minecraft-extras exception handlers MinecraftExceptionHandler.create(CommandCause::audience) - .defaultHandlers() - .decorator(message -> Component.text().append(COMMAND_PREFIX, space(), message).build()) - .registerTo(this.commandManager); + .defaultHandlers() + .decorator(message -> Component.text().append(COMMAND_PREFIX, space(), message).build()) + .registerTo(this.commandManager); this.registerCommands(); } private void registerCommands() { this.commandManager.command(this.commandManager.commandBuilder("cloud_test1") - .permission("cloud.test1") - .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); + .permission("cloud.test1") + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); this.commandManager.command(this.commandManager.commandBuilder("cloud_test2") - .literal("test") - .literal("test1") - .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); + .literal("test") + .literal("test1") + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); final Command.Builder cloudTest3 = this.commandManager.commandBuilder("cloud_test3"); final Command.Builder test = cloudTest3.literal("test"); - this.commandManager.command(test.argument(StringArgument.single("string_arg")) - .literal("test2") - .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); + this.commandManager.command(test.required("string_arg", stringParser()) + .literal("test2") + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); this.commandManager.command(test.literal("literal_arg") - .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); this.commandManager.command(cloudTest3.literal("another_test") - .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); final Command.Builder cloud = this.commandManager.commandBuilder("cloud"); this.commandManager.command(cloud.literal("string_test") - .argument(StringArgument.single("single")) - .argument(StringArgument.quoted("quoted")) - .argument(StringArgument.greedy("greedy")) - .handler(ctx -> ctx.getSender().audience().sendMessage(text("success")))); + .required("single", stringParser(StringParser.StringMode.SINGLE)) + .required("quoted", stringParser(StringParser.StringMode.QUOTED)) + .required("greedy", stringParser(StringParser.StringMode.GREEDY)) + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); this.commandManager.command(cloud.literal("int_test") - .argument(IntegerArgument.of("any")) - .argument(IntegerArgument.newBuilder("gt0").withMin(1)) - .argument(IntegerArgument.newBuilder("lt100").withMax(99)) - .argument(IntegerArgument.newBuilder("5to20").withMin(5).withMax(20)) - .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); + .required("any", integerParser()) + .required("gt0", integerParser(1)) + .required("lt100", integerParser(Integer.MIN_VALUE, 99)) + .required("5to20", integerParser(5, 20)) + .handler(ctx -> ctx.sender().audience().sendMessage(text("success")))); this.commandManager.command(cloud.literal("enchantment_type_test") - .argument(RegistryEntryArgument.of("enchantment_type", EnchantmentType.class, RegistryTypes.ENCHANTMENT_TYPE)) - .argument(IntegerArgument.optional("level", 1)) - .handler(ctx -> { - final Object subject = ctx.sender().subject(); - if (!(subject instanceof Player)) { - ctx.sender().audience().sendMessage(text("This command is for players only!", RED)); - return; - } - final Player player = (Player) subject; - final Hotbar hotbar = player.inventory().hotbar(); - final int index = hotbar.selectedSlotIndex(); - final Slot slot = hotbar.slot(index).get(); - final InventoryTransactionResult.Poll result = slot.poll(); - if (result.type() != InventoryTransactionResult.Type.SUCCESS) { - player.sendMessage(text("You must hold an item to enchant!", RED)); - return; - } - final ItemStack modified = ItemStack.builder() - .fromItemStack(result.polledItem().createStack()) - .add(Keys.APPLIED_ENCHANTMENTS, ImmutableList.of( - Enchantment.of( - ctx.get("enchantment_type"), - ctx.get("level") - ) - )) - .build(); - slot.set(modified); - })); + .required("enchantment_type", registryEntryParser(EnchantmentType.class, RegistryTypes.ENCHANTMENT_TYPE)) + .optional("level", integerParser(), DefaultValue.constant(1)) + .handler(ctx -> { + final Object subject = ctx.sender().subject(); + if (!(subject instanceof Player)) { + ctx.sender().audience().sendMessage(text("This command is for players only!", RED)); + return; + } + final Player player = (Player) subject; + final Hotbar hotbar = player.inventory().hotbar(); + final int index = hotbar.selectedSlotIndex(); + final Slot slot = hotbar.slot(index).get(); + final InventoryTransactionResult.Poll result = slot.poll(); + if (result.type() != InventoryTransactionResult.Type.SUCCESS) { + player.sendMessage(text("You must hold an item to enchant!", RED)); + return; + } + final ItemStack modified = ItemStack.builder() + .fromItemStack(result.polledItem().createStack()) + .add(Keys.APPLIED_ENCHANTMENTS, ImmutableList.of( + Enchantment.of( + ctx.get("enchantment_type"), + ctx.get("level") + ) + )) + .build(); + slot.set(modified); + })); this.commandManager.command(cloud.literal("color_test") - .argument(NamedTextColorArgument.of("color")) - .argument(StringArgument.greedy("message")) - .handler(ctx -> { - ctx.sender().audience().sendMessage( - text(ctx.get("message"), ctx.get("color")) - ); - })); + .required("color", namedTextColorParser()) + .required("message", greedyStringParser()) + .handler(ctx -> { + ctx.sender().audience().sendMessage( + text(ctx.get("message"), ctx.get("color")) + ); + })); this.commandManager.command(cloud.literal("operator_test") - .argument(IntegerArgument.of("first")) - .argument(OperatorArgument.of("operator")) - .argument(IntegerArgument.of("second")) - .handler(ctx -> { - final int first = ctx.get("first"); - final int second = ctx.get("second"); - final Operator operator = ctx.get("operator"); - if (!(operator instanceof Operator.Simple)) { - ctx.sender().audience().sendMessage( - text("That type of operator is not applicable here!", RED) - ); - return; - } - ctx.sender().audience().sendMessage(text() - .color(AQUA) - .append(text(first)) - .append(space()) - .append(text(operator.asString(), BLUE)) - .append(space()) - .append(text(second)) - .append(space()) - .append(text('→', BLUE)) - .append(space()) - .append(text(((Operator.Simple) operator).apply(first, second))) + .required("first", integerParser()) + .required("operator", operatorParser()) + .required("second", integerParser()) + .handler(ctx -> { + final int first = ctx.get("first"); + final int second = ctx.get("second"); + final Operator operator = ctx.get("operator"); + if (!(operator instanceof Operator.Simple)) { + ctx.sender().audience().sendMessage( + text("That type of operator is not applicable here!", RED) ); - })); + return; + } + ctx.sender().audience().sendMessage(text() + .color(AQUA) + .append(text(first)) + .append(space()) + .append(text(operator.asString(), BLUE)) + .append(space()) + .append(text(second)) + .append(space()) + .append(text('→', BLUE)) + .append(space()) + .append(text(((Operator.Simple) operator).apply(first, second))) + ); + })); this.commandManager.command(cloud.literal("modifylevel") - .argument(OperatorArgument.of("operator")) - .argument(DoubleArgument.of("value")) - .handler(ctx -> { - final Object subject = ctx.sender().subject(); - if (!(subject instanceof Player)) { // todo: a solution to this - ctx.sender().audience().sendMessage(text("This command is for players only!", RED)); - return; - } - final Player player = (Player) subject; - final Operator operator = ctx.get("operator"); - final double value = ctx.get("value"); - if (operator == Operators.ASSIGN.get()) { - player.offer(Keys.EXPERIENCE, (int) value); - return; - } - if (!(operator instanceof Operator.Simple)) { - ctx.sender().audience().sendMessage( - text("That type of operator is not applicable here!", RED) - ); - return; - } - final int currentXp = player.get(Keys.EXPERIENCE).get(); - player.offer(Keys.EXPERIENCE, (int) ((Operator.Simple) operator).apply(currentXp, value)); - })); + .required("operator", operatorParser()) + .required("value", doubleParser()) + .handler(ctx -> { + final Object subject = ctx.sender().subject(); + if (!(subject instanceof Player)) { // todo: a solution to this + ctx.sender().audience().sendMessage(text("This command is for players only!", RED)); + return; + } + final Player player = (Player) subject; + final Operator operator = ctx.get("operator"); + final double value = ctx.get("value"); + if (operator == Operators.ASSIGN.get()) { + player.offer(Keys.EXPERIENCE, (int) value); + return; + } + if (!(operator instanceof Operator.Simple)) { + ctx.sender().audience().sendMessage( + text("That type of operator is not applicable here!", RED) + ); + return; + } + final int currentXp = player.get(Keys.EXPERIENCE).get(); + player.offer(Keys.EXPERIENCE, (int) ((Operator.Simple) operator).apply(currentXp, value)); + })); this.commandManager.command(cloud.literal("selectplayer") - .argument(SinglePlayerSelectorArgument.of("player")) - .handler(ctx -> { - final Player player = ctx.get("player").getSingle(); - ctx.sender().audience().sendMessage(Component.text().append( - text("Display name of selected player: ", GRAY), - player.displayName().get() - ).build()); - })); + .required("player", singlePlayerSelectorParser()) + .handler(ctx -> { + final Player player = ctx.get("player").getSingle(); + ctx.sender().audience().sendMessage(Component.text().append( + text("Display name of selected player: ", GRAY), + player.displayName().get() + ).build()); + })); this.commandManager.command(cloud.literal("world_test") - .argument(WorldArgument.of("world")) - .handler(ctx -> { - ctx.sender().audience().sendMessage(text(ctx.get("world").key().asString())); - })); + .required("world", worldParser()) + .handler(ctx -> { + ctx.sender().audience().sendMessage(text(ctx.get("world").key().asString())); + })); this.commandManager.command(cloud.literal("test_item") - .argument(ProtoItemStackArgument.of("item")) - .literal("is") - .argument(ItemStackPredicateArgument.of("predicate")) - .handler(ctx -> { - final ItemStack item = ctx.get("item").createItemStack(1, true); - final ItemStackPredicate predicate = ctx.get("predicate"); - final Component message = text(builder -> { - builder.append(item.get(Keys.DISPLAY_NAME).orElse(item.type().asComponent())) - .append(space()); - if (predicate.test(item)) { - builder.append(text("passes!", GREEN)); - return; - } - builder.append(text("does not pass!", RED)); - }); - ctx.sender().audience().sendMessage(message); - })); + .required("item", protoItemStackParser()) + .literal("is") + .required("predicate", itemStackPredicateParser()) + .handler(ctx -> { + final ItemStack item = ctx.get("item").createItemStack(1, true); + final ItemStackPredicate predicate = ctx.get("predicate"); + final Component message = text(builder -> { + builder.append(item.get(Keys.DISPLAY_NAME).orElse(item.type().asComponent())) + .append(space()); + if (predicate.test(item)) { + builder.append(text("passes!", GREEN)); + return; + } + builder.append(text("does not pass!", RED)); + }); + ctx.sender().audience().sendMessage(message); + })); this.commandManager.command(cloud.literal("test_entity_type") - .argument(RegistryEntryArgument.of("type", new TypeToken>() { - }, RegistryTypes.ENTITY_TYPE)) - .handler(ctx -> { - ctx.sender().audience().sendMessage(ctx.>get("type")); - })); - final Function, RegistryHolder> holderFunction = ctx -> ctx.getSender() - .location() - .map(Location::world) - .orElse(Sponge.server().worldManager().defaultWorld()); + .required("type", registryEntryParser(new TypeToken<>() {}, RegistryTypes.ENTITY_TYPE)) + .handler(ctx -> ctx.sender().audience().sendMessage(ctx.>get("type")))); + final Function, RegistryHolder> holderFunction = ctx -> ctx.sender() + .location() + .map(Location::world) + .orElse(Sponge.server().worldManager().defaultWorld()); this.commandManager.command(cloud.literal("test_biomes") - .argument(RegistryEntryArgument.of("biome", Biome.class, holderFunction, RegistryTypes.BIOME)) - .handler(ctx -> { - final ResourceKey biomeKey = holderFunction.apply(ctx) - .registry(RegistryTypes.BIOME) - .findValueKey(ctx.get("biome")) - .orElseThrow(IllegalStateException::new); - ctx.sender().audience().sendMessage(text(biomeKey.asString())); - })); + .required("biome", registryEntryParser(Biome.class, RegistryTypes.BIOME, holderFunction)) + .handler(ctx -> { + final ResourceKey biomeKey = holderFunction.apply(ctx) + .registry(RegistryTypes.BIOME) + .findValueKey(ctx.get("biome")) + .orElseThrow(IllegalStateException::new); + ctx.sender().audience().sendMessage(text(biomeKey.asString())); + })); this.commandManager.command(cloud.literal("test_sounds") - .argument(RegistryEntryArgument.of("type", SoundType.class, RegistryTypes.SOUND_TYPE)) - .handler(ctx -> { - ctx.sender().audience().sendMessage(text(ctx.get("type").key().asString())); - })); + .required("type", registryEntryParser(SoundType.class, RegistryTypes.SOUND_TYPE)) + .handler(ctx -> { + ctx.sender().audience().sendMessage(text(ctx.get("type").key().asString())); + })); this.commandManager.command(cloud.literal("summon_villager") - .argument(RegistryEntryArgument.of("type", VillagerType.class, RegistryTypes.VILLAGER_TYPE)) - .argument(RegistryEntryArgument.of("profession", ProfessionType.class, RegistryTypes.PROFESSION_TYPE)) - .handler(ctx -> { - final ServerLocation loc = ctx.sender().location().orElse(null); - if (loc == null) { - ctx.sender().audience().sendMessage(text("No location!")); - return; - } - final ServerWorld world = loc.world(); - final Villager villager = world.createEntity(EntityTypes.VILLAGER, loc.position()); - villager.offer(Keys.VILLAGER_TYPE, ctx.get("type")); - villager.offer(Keys.PROFESSION_TYPE, ctx.get("profession")); - if (world.spawnEntity(villager)) { - ctx.sender().audience().sendMessage(text() - .append(text("Spawned entity!", GREEN)) - .append(space()) - .append(villager.displayName().get()) - .hoverEvent(villager)); - } else { - ctx.sender().audience().sendMessage(text("failed to spawn :(")); - } - })); + .required("type", registryEntryParser(VillagerType.class, RegistryTypes.VILLAGER_TYPE)) + .required("profession", registryEntryParser(ProfessionType.class, RegistryTypes.PROFESSION_TYPE)) + .handler(ctx -> { + final ServerLocation loc = ctx.sender().location().orElse(null); + if (loc == null) { + ctx.sender().audience().sendMessage(text("No location!")); + return; + } + final ServerWorld world = loc.world(); + final Villager villager = world.createEntity(EntityTypes.VILLAGER, loc.position()); + villager.offer(Keys.VILLAGER_TYPE, ctx.get("type")); + villager.offer(Keys.PROFESSION_TYPE, ctx.get("profession")); + if (world.spawnEntity(villager)) { + ctx.sender().audience().sendMessage(text() + .append(text("Spawned entity!", GREEN)) + .append(space()) + .append(villager.displayName().get()) + .hoverEvent(villager)); + } else { + ctx.sender().audience().sendMessage(text("failed to spawn :(")); + } + })); this.commandManager.command(cloud.literal("vec3d") - .argument(Vector3dArgument.of("vec3d")) - .handler(ctx -> { - ctx.sender().audience().sendMessage(text(ctx.get("vec3d").toString())); - })); + .required("vec3d", vector3dParser()) + .handler(ctx -> { + ctx.sender().audience().sendMessage(text(ctx.get("vec3d").toString())); + })); this.commandManager.command(cloud.literal("selectentities") - .argument(MultipleEntitySelectorArgument.of("selector")) - .handler(ctx -> { - final MultipleEntitySelector selector = ctx.get("selector"); - ctx.sender().audience().sendMessage(Component.text().append( - text("Using selector: ", BLUE), - text(selector.inputString()), - newline(), - text("Selected: ", LIGHT_PURPLE), - selector.get().stream() - .map(e -> e.displayName().get()) - .collect(Component.toComponent(text(", ", GRAY))) - ).build()); - })); + .required("selector", multipleEntitySelectorParser()) + .handler(ctx -> { + final MultipleEntitySelector selector = ctx.get("selector"); + ctx.sender().audience().sendMessage(Component.text().append( + text("Using selector: ", BLUE), + text(selector.inputString()), + newline(), + text("Selected: ", LIGHT_PURPLE), + selector.get().stream() + .map(e -> e.displayName().get()) + .collect(Component.toComponent(text(", ", GRAY))) + ).build()); + })); this.commandManager.command(cloud.literal("user") - .argument(UserArgument.of("user")) - .handler(ctx -> { - ctx.sender().audience().sendMessage(text(ctx.get("user").toString())); - })); + .required("user", userParser()) + .handler(ctx -> { + ctx.sender().audience().sendMessage(text(ctx.get("user").toString())); + })); this.commandManager.command(cloud.literal("data") - .argument(DataContainerArgument.of("data")) - .handler(ctx -> { - ctx.sender().audience().sendMessage(text(ctx.get("data").toString())); - })); + .required("data", dataContainerParser()) + .handler(ctx -> { + ctx.sender().audience().sendMessage(text(ctx.get("data").toString())); + })); this.commandManager.command(cloud.literal("setblock") - .permission("cloud.setblock") - .argument(Vector3iArgument.of("position")) - .argument(BlockInputArgument.of("block")) - .handler(ctx -> { - final Vector3i position = ctx.get("position"); - final BlockInput input = ctx.get("block"); - final Optional location = ctx.sender().location(); - if (location.isPresent()) { - final ServerWorld world = location.get().world(); - input.place(world.location(position)); - ctx.sender().audience().sendMessage(text("set block!")); - } else { - ctx.sender().audience().sendMessage(text("no location!")); - } - })); + .permission("cloud.setblock") + .required("position", vector3iParser()) + .required("block", blockInputParser()) + .handler(ctx -> { + final Vector3i position = ctx.get("position"); + final BlockInput input = ctx.get("block"); + final Optional location = ctx.sender().location(); + if (location.isPresent()) { + final ServerWorld world = location.get().world(); + input.place(world.location(position)); + ctx.sender().audience().sendMessage(text("set block!")); + } else { + ctx.sender().audience().sendMessage(text("no location!")); + } + })); this.commandManager.command(cloud.literal("blockinput") - .argument(BlockInputArgument.of("block")) - .handler(ctx -> { - final BlockInput input = ctx.get("block"); - ctx.sender().audience().sendMessage(text( - PaletteTypes.BLOCK_STATE_PALETTE.get().stringifier() - .apply(RegistryTypes.BLOCK_TYPE.get(), input.blockState()) - )); - })); + .required("block", blockInputParser()) + .handler(ctx -> { + final BlockInput input = ctx.get("block"); + ctx.sender().audience().sendMessage(text( + PaletteTypes.BLOCK_STATE_PALETTE.get().stringifier() + .apply(RegistryTypes.BLOCK_TYPE.get(), input.blockState()) + )); + })); this.commandManager.command(this.commandManager.commandBuilder("gib") - .permission("cloud.gib") - .argumentPair( - "itemstack", - TypeToken.get(ItemStack.class), - Pair.of("item", "amount"), - Pair.of(ProtoItemStack.class, Integer.class), - (sender, pair) -> { - final ProtoItemStack proto = pair.getFirst(); - final int amount = pair.getSecond(); - return proto.createItemStack(amount, true); - }, - ArgumentDescription.of("The ItemStack to give") - ) - .handler(ctx -> ((Player) ctx.getSender().subject()).inventory().offer(ctx.get("itemstack")))); + .permission("cloud.gib") + .requiredArgumentPair( + "itemstack", + TypeToken.get(ItemStack.class), + Pair.of("item", "amount"), + Pair.of(ProtoItemStack.class, Integer.class), + (sender, pair) -> { + final ProtoItemStack proto = pair.first(); + final int amount = pair.second(); + return proto.createItemStack(amount, true); + }, + Description.of("The ItemStack to give") + ) + .handler(ctx -> ((Player) ctx.sender().subject()).inventory().offer(ctx.get("itemstack")))); this.commandManager.command(cloud.literal("replace") - .permission(cause -> { - // works but error message is ugly - // todo: cause.cause().root() returns DedicatedServer during permission checks? - return cause.subject() instanceof Player; - }) - .argument(BlockPredicateArgument.of("predicate")) - .argument(IntegerArgument.of("radius")) - .argument(BlockInputArgument.of("replacement")) - .handler(ctx -> { - final BlockPredicate predicate = ctx.get("predicate"); - final int radius = ctx.get("radius"); - final BlockInput replacement = ctx.get("replacement"); + .permission(PredicatePermission.of(cause -> { + // works but error message is ugly + // todo: cause.cause().root() returns DedicatedServer during permission checks? + return cause.subject() instanceof Player; + })) + .required("predicate", blockPredicateParser()) + .required("radius", integerParser()) + .required("replacement", blockInputParser()) + .handler(ctx -> { + final BlockPredicate predicate = ctx.get("predicate"); + final int radius = ctx.get("radius"); + final BlockInput replacement = ctx.get("replacement"); - // its a player so get is fine - final ServerLocation loc = ctx.sender().location().get(); - final ServerWorld world = loc.world(); - final Vector3d vec = loc.position(); + // its a player so get is fine + final ServerLocation loc = ctx.sender().location().get(); + final ServerWorld world = loc.world(); + final Vector3d vec = loc.position(); - for (double x = vec.x() - radius; x < vec.x() + radius; x++) { - for (double y = vec.y() - radius; y < vec.y() + radius; y++) { - for (double z = vec.z() - radius; z < vec.z() + radius; z++) { - final ServerLocation location = world.location(x, y, z); - if (predicate.test(location)) { - location.setBlock(replacement.blockState()); - } + for (double x = vec.x() - radius; x < vec.x() + radius; x++) { + for (double y = vec.y() - radius; y < vec.y() + radius; y++) { + for (double z = vec.z() - radius; z < vec.z() + radius; z++) { + final ServerLocation location = world.location(x, y, z); + if (predicate.test(location)) { + location.setBlock(replacement.blockState()); } } } - })); + } + })); } }