From 9276a919d3213bcc363609e709013b14a1948392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Tue, 5 Jan 2021 11:05:39 +0100 Subject: [PATCH] :sparkles: Add keyed values to CommandContext and do some cleanup --- build.gradle.kts | 10 +- .../cloud/commandframework/CommandTree.java | 18 +- .../arguments/CommandArgument.java | 15 +- .../arguments/compound/FlagArgument.java | 14 +- .../context/CommandContext.java | 157 +++++++++++++++++- .../cloud/commandframework/keys/CloudKey.java | 53 ++++++ .../commandframework/keys/CloudKeyHolder.java | 44 +++++ .../commandframework/keys/SimpleCloudKey.java | 109 ++++++++++++ .../commandframework/keys/package-info.java | 30 ++++ .../commandframework/meta/CommandMeta.java | 11 +- .../bungee/BungeeCommandPreprocessor.java | 2 +- .../bungee/BungeeContextKeys.java | 50 ++++++ .../velocity/VelocityCommandPreprocessor.java | 5 +- .../velocity/VelocityContextKeys.java | 50 ++++++ 14 files changed, 544 insertions(+), 24 deletions(-) create mode 100644 cloud-core/src/main/java/cloud/commandframework/keys/CloudKey.java create mode 100644 cloud-core/src/main/java/cloud/commandframework/keys/CloudKeyHolder.java create mode 100644 cloud-core/src/main/java/cloud/commandframework/keys/SimpleCloudKey.java create mode 100644 cloud-core/src/main/java/cloud/commandframework/keys/package-info.java create mode 100644 cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeContextKeys.java create mode 100644 cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityContextKeys.java diff --git a/build.gradle.kts b/build.gradle.kts index 6d05c83a..223f963d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -170,10 +170,12 @@ subprojects { } signing { - isRequired = project.hasProperty("signing.keyId") - && (gradle.taskGraph.hasTask(":publish") - || gradle.taskGraph.hasTask(":publishToSonatype") - || gradle.taskGraph.hasTask(":publishToMavenLocal")) + gradle.taskGraph.whenReady { + isRequired = project.hasProperty("signing.keyId") + && (gradle.taskGraph.hasTask(":publish") + || gradle.taskGraph.hasTask(":publishToSonatype") + || gradle.taskGraph.hasTask(":publishToMavenLocal")) + } sign(publishing.publications["mavenJava"]) } diff --git a/cloud-core/src/main/java/cloud/commandframework/CommandTree.java b/cloud-core/src/main/java/cloud/commandframework/CommandTree.java index 42715f20..3c9198e8 100644 --- a/cloud-core/src/main/java/cloud/commandframework/CommandTree.java +++ b/cloud-core/src/main/java/cloud/commandframework/CommandTree.java @@ -36,10 +36,13 @@ import cloud.commandframework.exceptions.InvalidSyntaxException; import cloud.commandframework.exceptions.NoCommandInLeafException; import cloud.commandframework.exceptions.NoPermissionException; import cloud.commandframework.exceptions.NoSuchCommandException; +import cloud.commandframework.keys.CloudKey; +import cloud.commandframework.keys.SimpleCloudKey; import cloud.commandframework.permission.CommandPermission; import cloud.commandframework.permission.OrPermission; import cloud.commandframework.types.tuples.Pair; import io.leangen.geantyref.GenericTypeReflector; +import io.leangen.geantyref.TypeToken; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -90,6 +93,15 @@ import java.util.stream.Stream; */ public final class CommandTree { + /** + * Stores the index of the argument that is currently being parsed when parsing + * a {@link CompoundArgument} + */ + public static final CloudKey PARSING_ARGUMENT_KEY = SimpleCloudKey.of( + "__parsing_argument__", + TypeToken.get(Integer.class) + ); + private final Object commandLock = new Object(); private final Node> internalTree = new Node<>(null); @@ -569,7 +581,7 @@ public final class CommandTree { /* Attempt to pop as many arguments from the stack as possible */ for (int i = 0; i < requiredArguments - 1 && commandQueue.size() > 1; i++) { commandQueue.remove(); - commandContext.store("__parsing_argument__", i + 2); + commandContext.store(PARSING_ARGUMENT_KEY, i + 2); } } } else if (child.getValue().getParser() instanceof FlagArgument.FlagArgumentParser) { @@ -585,9 +597,7 @@ public final class CommandTree { @SuppressWarnings("unchecked") FlagArgument.FlagArgumentParser parser = (FlagArgument.FlagArgumentParser) child.getValue().getParser(); Optional lastFlag = parser.parseCurrentFlag(commandContext, commandQueue); - if (lastFlag.isPresent()) { - commandContext.store(FlagArgument.FLAG_META, lastFlag.get()); - } + lastFlag.ifPresent(s -> commandContext.store(FlagArgument.FLAG_META_KEY, s)); } else if (GenericTypeReflector.erase(child.getValue().getValueType().getType()).isArray()) { while (commandQueue.size() > 1) { commandQueue.remove(); diff --git a/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java b/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java index 5bbf6070..2c6850e0 100644 --- a/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java +++ b/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java @@ -29,6 +29,9 @@ import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ParserParameters; import cloud.commandframework.context.CommandContext; +import cloud.commandframework.keys.CloudKey; +import cloud.commandframework.keys.CloudKeyHolder; +import cloud.commandframework.keys.SimpleCloudKey; import io.leangen.geantyref.TypeToken; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -49,13 +52,17 @@ import java.util.regex.Pattern; * @param The type that the argument parses into */ @SuppressWarnings("unused") -public class CommandArgument implements Comparable> { +public class CommandArgument implements Comparable>, CloudKeyHolder { /** * Pattern for command argument names */ private static final Pattern NAME_PATTERN = Pattern.compile("[A-Za-z0-9\\-_]+"); + /** + * A typed key representing this argument + */ + private final CloudKey key; /** * Indicates whether or not the argument is required * or not. All arguments prior to any other required @@ -132,6 +139,7 @@ public class CommandArgument implements Comparable> ? buildDefaultSuggestionsProvider(this) : suggestionsProvider; this.argumentPreprocessors = new LinkedList<>(argumentPreprocessors); + this.key = SimpleCloudKey.of(this.name, this.valueType); } /** @@ -231,6 +239,11 @@ public class CommandArgument implements Comparable> return new Builder<>(TypeToken.get(clazz), name); } + @Override + public final @NonNull CloudKey getKey() { + return this.key; + } + /** * Check whether or not the command argument is required * diff --git a/cloud-core/src/main/java/cloud/commandframework/arguments/compound/FlagArgument.java b/cloud-core/src/main/java/cloud/commandframework/arguments/compound/FlagArgument.java index 0a9875d0..a6fea3fd 100644 --- a/cloud-core/src/main/java/cloud/commandframework/arguments/compound/FlagArgument.java +++ b/cloud-core/src/main/java/cloud/commandframework/arguments/compound/FlagArgument.java @@ -32,6 +32,9 @@ import cloud.commandframework.captions.CaptionVariable; import cloud.commandframework.captions.StandardCaptionKeys; import cloud.commandframework.context.CommandContext; import cloud.commandframework.exceptions.parsing.ParserException; +import cloud.commandframework.keys.CloudKey; +import cloud.commandframework.keys.SimpleCloudKey; +import io.leangen.geantyref.TypeToken; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Collection; @@ -64,8 +67,15 @@ public final class FlagArgument extends CommandArgument { public static final Object FLAG_PARSE_RESULT_OBJECT = new Object(); /** * Meta data for the last argument that was suggested + * + * @deprecated Use {@link #FLAG_META_KEY} instead */ + @Deprecated public static final String FLAG_META = "__last_flag__"; + /** + * Meta data for the last argument that was suggested + */ + public static final CloudKey FLAG_META_KEY = SimpleCloudKey.of("__last_flag__", TypeToken.get(String.class)); private static final String FLAG_ARGUMENT_NAME = "flags"; @@ -174,7 +184,7 @@ public final class FlagArgument extends CommandArgument { final @NonNull String input ) { /* Check if we have a last flag stored */ - final String lastArg = commandContext.getOrDefault(FLAG_META, ""); + final String lastArg = commandContext.getOrDefault(FLAG_META_KEY, ""); if (lastArg.isEmpty() || !lastArg.startsWith("-")) { final String rawInput = commandContext.getRawInputJoined(); /* Collection containing all used flags */ @@ -274,7 +284,7 @@ public final class FlagArgument extends CommandArgument { .apply(commandContext, input); } } - commandContext.store(FLAG_META, ""); + commandContext.store(FLAG_META_KEY, ""); return suggestions(commandContext, input); } diff --git a/cloud-core/src/main/java/cloud/commandframework/context/CommandContext.java b/cloud-core/src/main/java/cloud/commandframework/context/CommandContext.java index 582926d0..141b9b30 100644 --- a/cloud-core/src/main/java/cloud/commandframework/context/CommandContext.java +++ b/cloud-core/src/main/java/cloud/commandframework/context/CommandContext.java @@ -33,6 +33,9 @@ import cloud.commandframework.captions.CaptionRegistry; import cloud.commandframework.captions.CaptionVariable; import cloud.commandframework.captions.CaptionVariableReplacementHandler; import cloud.commandframework.captions.SimpleCaptionVariableReplacementHandler; +import cloud.commandframework.keys.CloudKey; +import cloud.commandframework.keys.CloudKeyHolder; +import cloud.commandframework.keys.SimpleCloudKey; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -54,7 +57,7 @@ public final class CommandContext { new SimpleCaptionVariableReplacementHandler(); private final Map, ArgumentTiming> argumentTimings = new HashMap<>(); private final FlagContext flagContext = FlagContext.create(); - private final Map internalStorage = new HashMap<>(); + private final Map, Object> internalStorage = new HashMap<>(); private final C commandSender; private final boolean suggestions; private final CaptionRegistry captionRegistry; @@ -168,9 +171,33 @@ public final class CommandContext { * @param Value type */ public void store(final @NonNull String key, final @NonNull T value) { + this.internalStorage.put(SimpleCloudKey.of(key), value); + } + + /** + * Store a value in the context map. This will overwrite any existing + * value stored with the same key + * + * @param key Key + * @param value Value + * @param Value type + */ + public void store(final @NonNull CloudKey key, final @NonNull T value) { this.internalStorage.put(key, value); } + /** + * Store a value in the context map. This will overwrite any existing + * value stored with the same key + * + * @param keyHolder Holder of the identifying key + * @param value Value + * @param Value type + */ + public void store(final @NonNull CloudKeyHolder keyHolder, final @NonNull T value) { + this.internalStorage.put(keyHolder.getKey(), value); + } + /** * Store or remove a value in the context map. This will overwrite any existing * value stored with the same key. @@ -190,6 +217,25 @@ public final class CommandContext { } } + /** + * Store or remove a value in the context map. This will overwrite any existing + * value stored with the same key. + *

+ * If the provided value is {@code null}, any current value stored for the provided key will be removed. + * + * @param key Key + * @param value Value + * @param Value type + * @since 1.4.0 + */ + public void set(final @NonNull CloudKey key, final @Nullable T value) { + if (value != null) { + this.store(key, value); + } else { + this.remove(key); + } + } + /** * Check if the context has a value stored for a key * @@ -198,6 +244,17 @@ public final class CommandContext { * @since 1.3.0 */ public boolean contains(final @NonNull String key) { + return this.contains(SimpleCloudKey.of(key)); + } + + /** + * Check if the context has a value stored for a key + * + * @param key Key + * @return Whether the context has a value for the provided key + * @since 1.4.0 + */ + public boolean contains(final @NonNull CloudKey key) { return this.internalStorage.containsKey(key); } @@ -208,7 +265,9 @@ public final class CommandContext { * @since 1.3.0 */ public @NonNull Map<@NonNull String, @Nullable ?> asMap() { - return Collections.unmodifiableMap(new HashMap<>(this.internalStorage)); + final Map values = new HashMap<>(); + this.internalStorage.forEach((key, value) -> values.put(key.getName(), value)); + return Collections.unmodifiableMap(values); } /** @@ -220,6 +279,25 @@ public final class CommandContext { * @return Value */ public @NonNull Optional getOptional(final @NonNull String key) { + final Object value = this.internalStorage.get(SimpleCloudKey.of(key)); + if (value != null) { + @SuppressWarnings("unchecked") final T castedValue = (T) value; + return Optional.of(castedValue); + } else { + return Optional.empty(); + } + } + + /** + * Get a value from its key. Will return {@link Optional#empty()} + * if no value is stored with the given key + * + * @param key Key + * @param Value type + * @return Value + * @since 1.4.0 + */ + public @NonNull Optional getOptional(final @NonNull CloudKey key) { final Object value = this.internalStorage.get(key); if (value != null) { @SuppressWarnings("unchecked") final T castedValue = (T) value; @@ -233,13 +311,13 @@ public final class CommandContext { * Get a value from its key. Will return {@link Optional#empty()} * if no value is stored with the given key * - * @param argument Argument - * @param Value type + * @param keyHolder Holder of the key + * @param Value type * @return Value */ @SuppressWarnings("unused") - public @NonNull Optional getOptional(final @NonNull CommandArgument argument) { - final Object value = this.internalStorage.get(argument.getName()); + public @NonNull Optional getOptional(final @NonNull CloudKeyHolder keyHolder) { + final Object value = this.internalStorage.get(keyHolder.getKey()); if (value != null) { @SuppressWarnings("unchecked") final T castedValue = (T) value; return Optional.of(castedValue); @@ -254,6 +332,16 @@ public final class CommandContext { * @param key Key to remove */ public void remove(final @NonNull String key) { + this.remove(SimpleCloudKey.of(key)); + } + + /** + * Remove a stored value from the context + * + * @param key Key to remove + * @since 1.4.0 + */ + public void remove(final @NonNull CloudKey key) { this.internalStorage.remove(key); } @@ -268,6 +356,25 @@ public final class CommandContext { */ @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public @NonNull T get(final @NonNull String key) { + final Object value = this.internalStorage.get(SimpleCloudKey.of(key)); + if (value == null) { + throw new NullPointerException("No such object stored in the context: " + key); + } + return (T) value; + } + + /** + * Get a required argument from the context. This will thrown an exception + * if there's no value associated with the given key + * + * @param key Argument key + * @param Argument type + * @return Argument + * @throws NullPointerException If no such argument is stored + * @since 1.4.0 + */ + @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) + public @NonNull T get(final @NonNull CloudKey key) { final Object value = this.internalStorage.get(key); if (value == null) { throw new NullPointerException("No such object stored in the context: " + key); @@ -279,13 +386,13 @@ public final class CommandContext { * Get a required argument from the context. This will thrown an exception * if there's no value associated with the given argument * - * @param argument The argument + * @param keyHolder Holder of the identifying key * @param Argument type * @return Stored value * @throws NullPointerException If no such value is stored */ - public @NonNull T get(final @NonNull CommandArgument argument) { - return this.get(argument.getName()); + public @NonNull T get(final @NonNull CloudKeyHolder keyHolder) { + return this.get(keyHolder.getKey()); } /** @@ -318,6 +425,22 @@ public final class CommandContext { return this.getOptional(key).orElse(defaultValue); } + /** + * Get a value if it exists, else return the provided default value + * + * @param key Argument key + * @param defaultValue Default value + * @param Argument type + * @return Argument, or supplied default value + * @since 1.4.0 + */ + public @Nullable T getOrDefault( + final @NonNull CloudKey key, + final @Nullable T defaultValue + ) { + return this.getOptional(key).orElse(defaultValue); + } + /** * Get a value if it exists, else return the value supplied by the given supplier * @@ -334,6 +457,22 @@ public final class CommandContext { return this.getOptional(key).orElseGet(defaultSupplier); } + /** + * Get a value if it exists, else return the value supplied by the given supplier + * + * @param key Argument key + * @param defaultSupplier Supplier of default value + * @param Argument type + * @return Argument, or supplied default value + * @since 1.4.0 + */ + public @Nullable T getOrSupplyDefault( + final @NonNull CloudKey key, + final @NonNull Supplier<@Nullable T> defaultSupplier + ) { + return this.getOptional(key).orElseGet(defaultSupplier); + } + /** * Get the raw input. This should only be used when {@link #isSuggestions()} is {@code true} * diff --git a/cloud-core/src/main/java/cloud/commandframework/keys/CloudKey.java b/cloud-core/src/main/java/cloud/commandframework/keys/CloudKey.java new file mode 100644 index 00000000..2faaa012 --- /dev/null +++ b/cloud-core/src/main/java/cloud/commandframework/keys/CloudKey.java @@ -0,0 +1,53 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package cloud.commandframework.keys; + +import io.leangen.geantyref.TypeToken; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * A typed, named key + * + * @param The type of the key + * @since 1.4.0 + */ +public interface CloudKey { + + /** + * Get the name of the key. The name of the key should be used to + * determine key equality. That means that two keys sharing the same + * name are equal. + * + * @return The key name + */ + @NonNull String getName(); + + /** + * Get the type of the value that this key holds. + * + * @return The type of the key value. + */ + @NonNull TypeToken<@NonNull T> getType(); + +} diff --git a/cloud-core/src/main/java/cloud/commandframework/keys/CloudKeyHolder.java b/cloud-core/src/main/java/cloud/commandframework/keys/CloudKeyHolder.java new file mode 100644 index 00000000..a07bd281 --- /dev/null +++ b/cloud-core/src/main/java/cloud/commandframework/keys/CloudKeyHolder.java @@ -0,0 +1,44 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package cloud.commandframework.keys; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Represents any object that holds a {@link CloudKey} + * + * @param The type of the key value. + * @since 1.4.0 + */ +@FunctionalInterface +public interface CloudKeyHolder { + + /** + * Get the key that identifies this object. + * + * @return Identifying key. + */ + @NonNull CloudKey getKey(); + +} diff --git a/cloud-core/src/main/java/cloud/commandframework/keys/SimpleCloudKey.java b/cloud-core/src/main/java/cloud/commandframework/keys/SimpleCloudKey.java new file mode 100644 index 00000000..e94c9359 --- /dev/null +++ b/cloud-core/src/main/java/cloud/commandframework/keys/SimpleCloudKey.java @@ -0,0 +1,109 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package cloud.commandframework.keys; + +import io.leangen.geantyref.TypeToken; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.Objects; + +/** + * Simple immutable implementation of {@link CloudKey}. Key equality is + * determined solely by the key name. Two keys with matching names will + * be equal, no matter if their type tokens are identical. + * + * @param Key type + * @since 1.4.0 + */ +public final class SimpleCloudKey<@NonNull T> implements CloudKey { + + private final String name; + private final TypeToken type; + + private SimpleCloudKey( + final @NonNull String name, + final @NonNull TypeToken type + ) { + this.name = name; + this.type = type; + } + + /** + * Create a new simple cloud key + * + * @param name The name of the key + * @param type The type of the value represented by the key + * @param The generic type of the value represented by the key + * @return The created key instance + */ + public static <@NonNull T> CloudKey of( + final @NonNull String name, + final @NonNull TypeToken type + ) { + return new SimpleCloudKey<>(name, type); + } + + /** + * Create a new type-less simple cloud key + * + * @param name The name of the key + * @return The created key instance + */ + public static @NonNull CloudKey of(final @NonNull String name) { + return new SimpleCloudKey<>(name, TypeToken.get(Void.TYPE)); + } + + @Override + public @NonNull String getName() { + return name; + } + + @Override + public @NonNull TypeToken getType() { + return this.type; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final SimpleCloudKey key = (SimpleCloudKey) o; + return name.equals(key.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return this.name; + } + +} diff --git a/cloud-core/src/main/java/cloud/commandframework/keys/package-info.java b/cloud-core/src/main/java/cloud/commandframework/keys/package-info.java new file mode 100644 index 00000000..4c078ca8 --- /dev/null +++ b/cloud-core/src/main/java/cloud/commandframework/keys/package-info.java @@ -0,0 +1,30 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +/** + * Type-safe named keys. + * + * @since 1.4.0 + */ +package cloud.commandframework.keys; diff --git a/cloud-core/src/main/java/cloud/commandframework/meta/CommandMeta.java b/cloud-core/src/main/java/cloud/commandframework/meta/CommandMeta.java index 59ebd99e..bba15469 100644 --- a/cloud-core/src/main/java/cloud/commandframework/meta/CommandMeta.java +++ b/cloud-core/src/main/java/cloud/commandframework/meta/CommandMeta.java @@ -24,6 +24,7 @@ package cloud.commandframework.meta; import cloud.commandframework.Command; +import cloud.commandframework.keys.CloudKey; import io.leangen.geantyref.GenericTypeReflector; import io.leangen.geantyref.TypeToken; import org.checkerframework.checker.nullness.qual.NonNull; @@ -131,7 +132,7 @@ public abstract class CommandMeta { * @param value type * @since 1.3.0 */ - public interface Key { + public interface Key extends CloudKey { /** * Create a new metadata key. @@ -210,6 +211,12 @@ public abstract class CommandMeta { ); } + @Override + @NonNull + default TypeToken<@NonNull V> getType() { + return this.getValueType(); + } + /** * Get a representation of the type of value this key holds. * @@ -222,7 +229,7 @@ public abstract class CommandMeta { * * @return the key type */ - @NonNull String getName(); + @Override @NonNull String getName(); /** * Get a function that can be used to compute a fallback based on existing meta. diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandPreprocessor.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandPreprocessor.java index c80c3fbe..9b748726 100644 --- a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandPreprocessor.java +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeCommandPreprocessor.java @@ -49,7 +49,7 @@ final class BungeeCommandPreprocessor implements CommandPreprocessor { @Override public void accept(final @NonNull CommandPreprocessingContext context) { - context.getCommandContext().store("ProxyServer", mgr.getOwningPlugin().getProxy()); + context.getCommandContext().store(BungeeContextKeys.PROXY_SERVER_KEY, mgr.getOwningPlugin().getProxy()); } } diff --git a/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeContextKeys.java b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeContextKeys.java new file mode 100644 index 00000000..2bb1541d --- /dev/null +++ b/cloud-minecraft/cloud-bungee/src/main/java/cloud/commandframework/bungee/BungeeContextKeys.java @@ -0,0 +1,50 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package cloud.commandframework.bungee; + +import cloud.commandframework.keys.CloudKey; +import cloud.commandframework.keys.SimpleCloudKey; +import io.leangen.geantyref.TypeToken; +import net.md_5.bungee.api.ProxyServer; + +/** + * BungeeCord related {@link cloud.commandframework.context.CommandContext} keys + * + * @since 1.4.0 + */ +public final class BungeeContextKeys { + + /** + * The {@link ProxyServer} instance is stored in the {@link cloud.commandframework.context.CommandContext} + * in {@link BungeeCommandPreprocessor} + */ + public static final CloudKey PROXY_SERVER_KEY = SimpleCloudKey.of( + "ProxyServer", + TypeToken.get(ProxyServer.class) + ); + + private BungeeContextKeys() { + } + +} diff --git a/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityCommandPreprocessor.java b/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityCommandPreprocessor.java index 9ebc9f30..fddb0139 100644 --- a/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityCommandPreprocessor.java +++ b/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityCommandPreprocessor.java @@ -49,7 +49,10 @@ final class VelocityCommandPreprocessor implements CommandPreprocessor { @Override public void accept(final @NonNull CommandPreprocessingContext context) { - context.getCommandContext().store("ProxyServer", mgr.getProxyServer()); + context.getCommandContext().store( + VelocityContextKeys.PROXY_SERVER_KEY, + mgr.getProxyServer() + ); } } diff --git a/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityContextKeys.java b/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityContextKeys.java new file mode 100644 index 00000000..4dc76b6e --- /dev/null +++ b/cloud-minecraft/cloud-velocity/src/main/java/cloud/commandframework/velocity/VelocityContextKeys.java @@ -0,0 +1,50 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package cloud.commandframework.velocity; + +import cloud.commandframework.keys.CloudKey; +import cloud.commandframework.keys.SimpleCloudKey; +import com.velocitypowered.api.proxy.ProxyServer; +import io.leangen.geantyref.TypeToken; + +/** + * Velocity related {@link cloud.commandframework.context.CommandContext} keys + * + * @since 1.4.0 + */ +public final class VelocityContextKeys { + + /** + * The {@link ProxyServer} instance is stored in the {@link cloud.commandframework.context.CommandContext} + * in {@link VelocityCommandPreprocessor} + */ + public static final CloudKey PROXY_SERVER_KEY = SimpleCloudKey.of( + "ProxyServer", + TypeToken.get(ProxyServer.class) + ); + + private VelocityContextKeys() { + } + +}