fabric: work

This commit is contained in:
Zach Levis 2021-01-11 20:30:36 -08:00 committed by Jason
parent 6eae149089
commit 3f67a1ae04
11 changed files with 303 additions and 3 deletions

View file

@ -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<C> extends FabricCommandManager<C,
null
)
);
this.registerParsers();
}
private void registerParsers() {
this.getParserRegistry().registerParserSupplier(TypeToken.get(Message.class), params -> FabricArgumentParsers.message());
}
/**

View file

@ -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 <C> ArgumentParser<C, Message> message() {
return new WrappedBrigadierParser<C, MessageArgumentType.MessageFormat>(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<Entity> 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<Entity> 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<Entity> mentionedEntities, final Text contents) {
this.mentionedEntities = mentionedEntities;
this.contents = contents;
}
@Override
public Collection<Entity> getMentionedEntities() {
return this.mentionedEntities;
}
@Override
public Text getContents() {
return this.contents;
}
}
}

View file

@ -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 <C> the sender type
* @since 1.4.0
*/
public final class MessageArgument<C> extends CommandArgument<C, Message> {
MessageArgument(
final boolean required,
final @NonNull String name,
final @NonNull String defaultValue,
final @Nullable BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider
) {
super(
required,
name,
FabricArgumentParsers.message(),
defaultValue,
Message.class,
suggestionsProvider
);
}
/**
* Create a new builder.
*
* @param name Name of the argument
* @param <C> Command sender type
* @return Created builder
*/
public static <C> MessageArgument.@NonNull Builder<C> newBuilder(final @NonNull String name) {
return new MessageArgument.Builder<>(name);
}
/**
* Create a new required command argument.
*
* @param name Component name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull MessageArgument<C> of(final @NonNull String name) {
return MessageArgument.<C>newBuilder(name).asRequired().build();
}
/**
* Create a new optional command argument
*
* @param name Component name
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull MessageArgument<C> optional(final @NonNull String name) {
return MessageArgument.<C>newBuilder(name).asOptional().build();
}
/**
* Create a new optional command argument with a default value
*
* @param name Argument name
* @param defaultValue Default value
* @param <C> Command sender type
* @return Created argument
*/
public static <C> @NonNull MessageArgument<C> optional(
final @NonNull String name,
final String defaultValue
) {
return MessageArgument.<C>newBuilder(name).asOptionalWithDefault(defaultValue).build();
}
public static final class Builder<C> extends TypedBuilder<C, Message, Builder<C>> {
Builder(final @NonNull String name) {
super(Message.class, name);
}
/**
* Build a new criterion argument
*
* @return Constructed argument
*/
@Override
public @NonNull MessageArgument<C> build() {
return new MessageArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(), this.getSuggestionsProvider());
}
}
}

View file

@ -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<Entity> getMentionedEntities();
Text getContents();
}

View file

@ -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<GameProfile> {
@Override
public String getInput() {
return null;
}
@Override
public @Nullable EntitySelector getSelector() {
return null;
}
@Override
public Collection<GameProfile> get() {
return null;
}
}

View file

@ -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<V> {
*/
interface Single<V> extends Selector<V> {
@Override
default Collection<V> get() {
return Collections.singletonList(this.getSingle());
}
V getSingle();
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -4,7 +4,9 @@
"required": true,
"mixins": [
"CloudStringReaderMixin",
"CommandManagerMixin"
"CommandManagerMixin",
"MessageArgumentTypeMessageFormatAccess",
"MessageArgumentTypeMessageSelectorAccess"
],
"injectors": {
"defaultRequire": 1

View file

@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"id": "cloud",
"id": "cloud-v1",
"version": "${version}",
"name": "Cloud",

View file

@ -23,6 +23,6 @@
"fabricloader": ">=0.7.4",
"fabric-command-api-v1": "*",
"minecraft": ">=1.14",
"cloud": "*"
"cloud-v1": "*"
}
}