From 3f67a1ae048314af18d4fec88ae294fedb769a42 Mon Sep 17 00:00:00 2001 From: Zach Levis Date: Mon, 11 Jan 2021 20:30:36 -0800 Subject: [PATCH] fabric: work --- .../fabric/FabricServerCommandManager.java | 10 ++ .../argument/FabricArgumentParsers.java | 74 +++++++++ .../argument/server/MessageArgument.java | 142 ++++++++++++++++++ .../commandframework/fabric/data/Message.java | 17 +++ .../data/MultipleGameProfileSelector.java | 26 ++++ .../fabric/data/Selector.java | 6 + ...essageArgumentTypeMessageFormatAccess.java | 12 ++ ...sageArgumentTypeMessageSelectorAccess.java | 11 ++ .../src/main/resources/cloud.mixins.json | 4 +- .../src/main/resources/fabric.mod.json | 2 +- .../src/testmod/resources/fabric.mod.json | 2 +- 11 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/MessageArgument.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Message.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/MultipleGameProfileSelector.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageFormatAccess.java create mode 100644 cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageSelectorAccess.java diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java index b9156539..1564aba5 100644 --- a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/FabricServerCommandManager.java @@ -27,7 +27,11 @@ package cloud.commandframework.fabric; import cloud.commandframework.CommandTree; import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator; import cloud.commandframework.execution.CommandExecutionCoordinator; +import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.argument.server.MessageArgument; +import cloud.commandframework.fabric.data.Message; import cloud.commandframework.meta.CommandMeta; +import io.leangen.geantyref.TypeToken; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandOutput; @@ -110,6 +114,12 @@ public final class FabricServerCommandManager extends FabricCommandManager FabricArgumentParsers.message()); } /** diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java index c2980612..6b183a6a 100644 --- a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/FabricArgumentParsers.java @@ -28,11 +28,24 @@ import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; import cloud.commandframework.fabric.FabricCommandContextKeys; +import cloud.commandframework.fabric.argument.server.MessageArgument; +import cloud.commandframework.fabric.data.Message; import cloud.commandframework.fabric.data.MinecraftTime; +import cloud.commandframework.fabric.mixin.MessageArgumentTypeMessageFormatAccess; +import cloud.commandframework.fabric.mixin.MessageArgumentTypeMessageSelectorAccess; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.command.CommandSource; import net.minecraft.command.argument.FunctionArgumentType; +import net.minecraft.command.argument.MessageArgumentType; import net.minecraft.command.argument.TimeArgumentType; +import net.minecraft.entity.Entity; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.function.CommandFunction; +import net.minecraft.text.Text; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; /** * Parsers for Vanilla command argument types. @@ -64,4 +77,65 @@ public final class FabricArgumentParsers { }) } + public static ArgumentParser message() { + return new WrappedBrigadierParser(MessageArgumentType.message()) + .map((ctx, format) -> { + final CommandSource either = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE); + if (!(either instanceof ServerCommandSource)) { + return ArgumentParseResult.failure(new IllegalStateException("This argument is server-only")); + } + try { + return ArgumentParseResult.success(MessageImpl.from( + (ServerCommandSource) either, + format, + true + )); + } catch (final CommandSyntaxException ex) { + return ArgumentParseResult.failure(ex); + } + }); + } + + static final class MessageImpl implements Message { + private final Collection mentionedEntities; + private final Text contents; + + static MessageImpl from( + final ServerCommandSource source, + final MessageArgumentType.MessageFormat message, + final boolean useSelectors + ) throws CommandSyntaxException { + final Text contents = message.format(source, useSelectors); + final MessageArgumentType.MessageSelector[] selectors = + ((MessageArgumentTypeMessageFormatAccess) message).accessor$selectors(); + final Collection entities; + if (!useSelectors || selectors.length == 0) { + entities = Collections.emptySet(); + } else { + entities = new HashSet<>(); + for (final MessageArgumentType.MessageSelector selector : selectors) { + entities.addAll(((MessageArgumentTypeMessageSelectorAccess) selector).accessor$selector().getEntities(source)); + } + } + + return new MessageImpl(entities, contents); + } + + MessageImpl(final Collection mentionedEntities, final Text contents) { + this.mentionedEntities = mentionedEntities; + this.contents = contents; + } + + @Override + public Collection getMentionedEntities() { + return this.mentionedEntities; + } + + @Override + public Text getContents() { + return this.contents; + } + + } + } diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/MessageArgument.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/MessageArgument.java new file mode 100644 index 00000000..a517e703 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/argument/server/MessageArgument.java @@ -0,0 +1,142 @@ +// +// 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.fabric.argument.server; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.fabric.FabricCommandContextKeys; +import cloud.commandframework.fabric.argument.FabricArgumentParsers; +import cloud.commandframework.fabric.data.Message; +import cloud.commandframework.fabric.mixin.MessageArgumentTypeMessageFormatAccess; +import cloud.commandframework.fabric.mixin.MessageArgumentTypeMessageSelectorAccess; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.command.CommandSource; +import net.minecraft.command.argument.MessageArgumentType; +import net.minecraft.entity.Entity; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.function.BiFunction; + +/** + * An argument similar to a greedy string, but one that resolves selectors. + * + * @param the sender type + * @since 1.4.0 + */ +public final class MessageArgument extends CommandArgument { + + MessageArgument( + final boolean required, + final @NonNull String name, + final @NonNull String defaultValue, + final @Nullable BiFunction, String, List> suggestionsProvider + ) { + super( + required, + name, + FabricArgumentParsers.message(), + defaultValue, + Message.class, + suggestionsProvider + ); + } + + /** + * Create a new builder. + * + * @param name Name of the argument + * @param Command sender type + * @return Created builder + */ + public static MessageArgument.@NonNull Builder newBuilder(final @NonNull String name) { + return new MessageArgument.Builder<>(name); + } + + /** + * Create a new required command argument. + * + * @param name Component name + * @param Command sender type + * @return Created argument + */ + public static @NonNull MessageArgument of(final @NonNull String name) { + return MessageArgument.newBuilder(name).asRequired().build(); + } + + /** + * Create a new optional command argument + * + * @param name Component name + * @param Command sender type + * @return Created argument + */ + public static @NonNull MessageArgument optional(final @NonNull String name) { + return MessageArgument.newBuilder(name).asOptional().build(); + } + + /** + * Create a new optional command argument with a default value + * + * @param name Argument name + * @param defaultValue Default value + * @param Command sender type + * @return Created argument + */ + public static @NonNull MessageArgument optional( + final @NonNull String name, + final String defaultValue + ) { + return MessageArgument.newBuilder(name).asOptionalWithDefault(defaultValue).build(); + } + + + public static final class Builder extends TypedBuilder> { + + Builder(final @NonNull String name) { + super(Message.class, name); + } + + /** + * Build a new criterion argument + * + * @return Constructed argument + */ + @Override + public @NonNull MessageArgument build() { + return new MessageArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(), this.getSuggestionsProvider()); + } + + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Message.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Message.java new file mode 100644 index 00000000..e6aea04a --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Message.java @@ -0,0 +1,17 @@ +package cloud.commandframework.fabric.data; + +import net.minecraft.entity.Entity; +import net.minecraft.text.Text; + +import java.util.Collection; + +/** + * A parsed message. + */ +public interface Message { + + Collection getMentionedEntities(); + + Text getContents(); + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/MultipleGameProfileSelector.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/MultipleGameProfileSelector.java new file mode 100644 index 00000000..4db23ca7 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/MultipleGameProfileSelector.java @@ -0,0 +1,26 @@ +package cloud.commandframework.fabric.data; + +import com.mojang.authlib.GameProfile; +import net.minecraft.command.EntitySelector; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Collection; + +public class MultipleGameProfileSelector implements Selector { + + @Override + public String getInput() { + return null; + } + + @Override + public @Nullable EntitySelector getSelector() { + return null; + } + + @Override + public Collection get() { + return null; + } + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Selector.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Selector.java index b2e5fc38..fd2b8137 100644 --- a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Selector.java +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/data/Selector.java @@ -4,6 +4,7 @@ import net.minecraft.command.EntitySelector; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collection; +import java.util.Collections; /** * A selector string to query multiple entity-like values @@ -42,6 +43,11 @@ public interface Selector { */ interface Single extends Selector { + @Override + default Collection get() { + return Collections.singletonList(this.getSingle()); + } + V getSingle(); } diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageFormatAccess.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageFormatAccess.java new file mode 100644 index 00000000..0b1d7185 --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageFormatAccess.java @@ -0,0 +1,12 @@ +package cloud.commandframework.fabric.mixin; + +import net.minecraft.command.argument.MessageArgumentType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MessageArgumentType.MessageFormat.class) +public interface MessageArgumentTypeMessageFormatAccess { + + @Accessor("selectors") MessageArgumentType.MessageSelector[] accessor$selectors(); + +} diff --git a/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageSelectorAccess.java b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageSelectorAccess.java new file mode 100644 index 00000000..7d55bd2d --- /dev/null +++ b/cloud-minecraft/cloud-fabric/src/main/java/cloud/commandframework/fabric/mixin/MessageArgumentTypeMessageSelectorAccess.java @@ -0,0 +1,11 @@ +package cloud.commandframework.fabric.mixin; + +import net.minecraft.command.EntitySelector; +import net.minecraft.command.argument.MessageArgumentType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MessageArgumentType.MessageSelector.class) +public interface MessageArgumentTypeMessageSelectorAccess { + @Accessor("selector") EntitySelector accessor$selector(); +} diff --git a/cloud-minecraft/cloud-fabric/src/main/resources/cloud.mixins.json b/cloud-minecraft/cloud-fabric/src/main/resources/cloud.mixins.json index e7d1ae12..529fd755 100644 --- a/cloud-minecraft/cloud-fabric/src/main/resources/cloud.mixins.json +++ b/cloud-minecraft/cloud-fabric/src/main/resources/cloud.mixins.json @@ -4,7 +4,9 @@ "required": true, "mixins": [ "CloudStringReaderMixin", - "CommandManagerMixin" + "CommandManagerMixin", + "MessageArgumentTypeMessageFormatAccess", + "MessageArgumentTypeMessageSelectorAccess" ], "injectors": { "defaultRequire": 1 diff --git a/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json b/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json index de9d621f..5ea317ef 100644 --- a/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json +++ b/cloud-minecraft/cloud-fabric/src/main/resources/fabric.mod.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "id": "cloud", + "id": "cloud-v1", "version": "${version}", "name": "Cloud", diff --git a/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json b/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json index 5396ad26..7144a098 100644 --- a/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json +++ b/cloud-minecraft/cloud-fabric/src/testmod/resources/fabric.mod.json @@ -23,6 +23,6 @@ "fabricloader": ">=0.7.4", "fabric-command-api-v1": "*", "minecraft": ">=1.14", - "cloud": "*" + "cloud-v1": "*" } }