Skip to content

Rewrite .setting for finer control and input suggestions #5178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

public abstract class Command {
protected static final CommandRegistryAccess REGISTRY_ACCESS = CommandManager.createRegistryAccess(BuiltinRegistries.createWrapperLookup());
protected static final int SINGLE_SUCCESS = com.mojang.brigadier.Command.SINGLE_SUCCESS;
protected static final MinecraftClient mc = MeteorClient.mc;
public static final int SINGLE_SUCCESS = com.mojang.brigadier.Command.SINGLE_SUCCESS;

private final String name;
private final String title;
Expand All @@ -40,11 +40,11 @@ public Command(String name, String description, String... aliases) {
}

// Helper methods to painlessly infer the CommandSource generic type argument
protected static <T> RequiredArgumentBuilder<CommandSource, T> argument(final String name, final ArgumentType<T> type) {
public static <T> RequiredArgumentBuilder<CommandSource, T> argument(final String name, final ArgumentType<T> type) {
return RequiredArgumentBuilder.argument(name, type);
}

protected static LiteralArgumentBuilder<CommandSource> literal(final String name) {
public static LiteralArgumentBuilder<CommandSource> literal(final String name) {
return LiteralArgumentBuilder.literal(name);
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.commands.arguments;

import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.CommandSource;

import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Supplier;

public class CollectionItemArgumentType<T> implements ArgumentType<T> {
private static final DynamicCommandExceptionType NO_SUCH_ITEM_EXCEPTION = new DynamicCommandExceptionType(o -> new LiteralMessage("No such item '" + o + "'."));
private final Supplier<Collection<T>> collection;
private final StringFunction<T> stringFunction;

public CollectionItemArgumentType(Supplier<Collection<T>> collection, StringFunction<T> stringFunction) {
this.collection = collection;
this.stringFunction = stringFunction;
}

public CollectionItemArgumentType(Supplier<Collection<T>> collection) {
this(collection, Object::toString);
}

@Override
public T parse(StringReader stringReader) throws CommandSyntaxException {
String value = stringReader.readString();

Optional<T> itemResult = this.collection.get().stream()
.filter(item -> this.stringFunction.apply(item).equals(value))
.findAny();

if (itemResult.isPresent()) {
return itemResult.get();
} else {
throw NO_SUCH_ITEM_EXCEPTION.create(value);
}
}

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return CommandSource.suggestMatching(this.collection.get().stream().map(this.stringFunction), builder);
}

@FunctionalInterface
public interface StringFunction<T> extends Function<T, String> {
String apply(T value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.commands.arguments;

import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import meteordevelopment.meteorclient.settings.ColorSetting;
import meteordevelopment.meteorclient.utils.render.color.SettingColor;

import java.util.Collection;

public class ColorArgumentType implements ArgumentType<SettingColor> {
private static final ColorArgumentType INSTANCE = new ColorArgumentType();

private ColorArgumentType() {}

public static ColorArgumentType color() {
return INSTANCE;
}

public static <S> SettingColor get(CommandContext<S> context, String name) {
return context.getArgument(name, SettingColor.class);
}

@Override
public SettingColor parse(StringReader stringReader) throws CommandSyntaxException {
int cursor = stringReader.getCursor();

try {
if (stringReader.readString().equals("rainbow")) {
return new SettingColor().rainbow(true);
}
} catch (CommandSyntaxException ignored) {}
stringReader.setCursor(cursor);

int red = readInt(stringReader);
int green = readInt(stringReader);
int blue = readInt(stringReader);
int alpha = 255;

if (stringReader.canRead() && StringReader.isAllowedNumber(stringReader.peek())) {
alpha = readInt(stringReader);
}

return new SettingColor(red, green, blue, alpha);
}

private static int readInt(StringReader reader) throws CommandSyntaxException {
int i = reader.readInt();
reader.skipWhitespace();
if (i < 0) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.integerTooLow().createWithContext(reader, i, 0);
} else if (i > 255) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.integerTooHigh().createWithContext(reader, i, 255);
} else {
return i;
}
}

@Override
public Collection<String> getExamples() {
return ColorSetting.SUGGESTIONS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.commands.arguments;

import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import meteordevelopment.meteorclient.renderer.Fonts;
import meteordevelopment.meteorclient.renderer.text.FontFace;
import meteordevelopment.meteorclient.renderer.text.FontFamily;
import meteordevelopment.meteorclient.renderer.text.FontInfo;
import meteordevelopment.meteorclient.settings.FontFaceSetting;
import net.minecraft.command.CommandSource;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class FontFaceArgumentType implements ArgumentType<FontFace> {
private static final FontFaceArgumentType INSTANCE = new FontFaceArgumentType();
private static final DynamicCommandExceptionType NO_SUCH_FONT_FACE_EXCEPTION = new DynamicCommandExceptionType(o -> new LiteralMessage("No such font face: ' " + o + "'"));

private FontFaceArgumentType() {}

public static FontFaceArgumentType fontFace() {
return INSTANCE;
}

public static <S> FontFace get(CommandContext<S> context, String name) {
return context.getArgument(name, FontFace.class);
}

@Override
public FontFace parse(StringReader stringReader) throws CommandSyntaxException {
String value = stringReader.readString();

String[] split = value.split("-");
if (split.length != 2) throw NO_SUCH_FONT_FACE_EXCEPTION.createWithContext(stringReader, value);

for (FontFamily family : Fonts.FONT_FAMILIES) {
if (family.getName().replace(" ", "").equals(split[0])) {
try {
return family.get(FontInfo.Type.valueOf(split[1]));
}
catch (IllegalArgumentException ignored) {
throw NO_SUCH_FONT_FACE_EXCEPTION.createWithContext(stringReader, value);
}
}
}

throw NO_SUCH_FONT_FACE_EXCEPTION.createWithContext(stringReader, value);
}

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
BiConsumer<FontFamily, Consumer<FontFace>> mapper = (family, c) -> {
for (FontInfo.Type type : FontInfo.Type.values()) {
@Nullable FontFace font = family.get(type);
if (font != null) {
c.accept(font);
}
}
};

return CommandSource.suggestMatching(Fonts.FONT_FAMILIES.stream().mapMulti(mapper).map(FontFaceArgumentType::stringify), builder);
}

private static String stringify(FontFace fontFace) {
String family = fontFace.info.family().replace(" ", "");
String type = fontFace.info.type().toString().replace(" ", "");
return family + "-" + type;
}

@Override
public Collection<String> getExamples() {
return FontFaceSetting.EXAMPLES;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.commands.arguments;

import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.block.Block;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.item.Item;
import net.minecraft.particle.ParticleType;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;

import java.util.concurrent.CompletableFuture;

public class RegistryEntryArgumentType<T> implements ArgumentType<RegistryEntry.Reference<T>> {
private static final RegistryEntryArgumentType<Block> BLOCK = new RegistryEntryArgumentType<>(Registries.BLOCK);
private static final RegistryEntryArgumentType<BlockEntityType<?>> BLOCK_ENTITY_TYPE = new RegistryEntryArgumentType<>(Registries.BLOCK_ENTITY_TYPE);
private static final RegistryEntryArgumentType<EntityType<?>> ENTITY_TYPE = new RegistryEntryArgumentType<>(Registries.ENTITY_TYPE);
private static final RegistryEntryArgumentType<Item> ITEM = new RegistryEntryArgumentType<>(Registries.ITEM);
private static final RegistryEntryArgumentType<ParticleType<?>> PARTICLE_TYPE = new RegistryEntryArgumentType<>(Registries.PARTICLE_TYPE);
private static final RegistryEntryArgumentType<ScreenHandlerType<?>> SCREEN_HANDLER = new RegistryEntryArgumentType<>(Registries.SCREEN_HANDLER);
private static final RegistryEntryArgumentType<SoundEvent> SOUND_EVENT = new RegistryEntryArgumentType<>(Registries.SOUND_EVENT);
private static final RegistryEntryArgumentType<StatusEffect> STATUS_EFFECT = new RegistryEntryArgumentType<>(Registries.STATUS_EFFECT);

public static final DynamicCommandExceptionType NOT_FOUND_EXCEPTION = new DynamicCommandExceptionType(
element -> new LiteralMessage("Not found exception type shii " + element)
);
public static final Dynamic3CommandExceptionType INVALID_TYPE_EXCEPTION = new Dynamic3CommandExceptionType(
(element, type, expectedType) -> Text.stringifiedTranslatable("argument.resource.invalid_type", element, type, expectedType)
);
private final Registry<T> registry;

private RegistryEntryArgumentType(Registry<T> registry) {
this.registry = registry;
}

public static RegistryEntryArgumentType<Block> block() {
return BLOCK;
}

public static RegistryEntryArgumentType<BlockEntityType<?>> blockEntityType() {
return BLOCK_ENTITY_TYPE;
}

public static RegistryEntryArgumentType<EntityType<?>> entityType() {
return ENTITY_TYPE;
}

public static RegistryEntryArgumentType<Item> item() {
return ITEM;
}

public static RegistryEntryArgumentType<ParticleType<?>> particleType() {
return PARTICLE_TYPE;
}

public static RegistryEntryArgumentType<ScreenHandlerType<?>> screenHandler() {
return SCREEN_HANDLER;
}

public static RegistryEntryArgumentType<SoundEvent> soundEvent() {
return SOUND_EVENT;
}

public static RegistryEntryArgumentType<StatusEffect> statusEffect() {
return STATUS_EFFECT;
}

public static <S> RegistryEntry.Reference<Block> getBlock(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.BLOCK);
}

public static <S> RegistryEntry.Reference<BlockEntityType<?>> getBlockEntityType(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.BLOCK_ENTITY_TYPE);
}

public static <S> RegistryEntry.Reference<EntityType<?>> getEntityType(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.ENTITY_TYPE);
}

public static <S> RegistryEntry.Reference<Item> getItem(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.ITEM);
}

public static <S> RegistryEntry.Reference<ParticleType<?>> getParticleType(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.PARTICLE_TYPE);
}

public static <S> RegistryEntry.Reference<ScreenHandlerType<?>> getScreenHandler(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.SCREEN_HANDLER);
}

public static <S> RegistryEntry.Reference<SoundEvent> getSoundEvent(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.SOUND_EVENT);
}

public static <S> RegistryEntry.Reference<StatusEffect> getStatusEffect(CommandContext<S> context, String name) throws CommandSyntaxException {
return getRegistryEntry(context, name, RegistryKeys.STATUS_EFFECT);
}

private static <T> RegistryEntry.Reference<T> getRegistryEntry(CommandContext<?> context, String name, RegistryKey<Registry<T>> registryRef) throws CommandSyntaxException {
RegistryEntry.Reference<T> reference = context.getArgument(name, RegistryEntry.Reference.class);
RegistryKey<?> registryKey = reference.registryKey();
if (registryKey.isOf(registryRef)) {
return reference;
} else {
throw INVALID_TYPE_EXCEPTION.create(registryKey.getValue(), registryKey.getRegistry(), registryRef.getValue());
}
}

@Override
public RegistryEntry.Reference<T> parse(StringReader stringReader) throws CommandSyntaxException {
Identifier identifier = Identifier.fromCommandInput(stringReader);
return this.registry.getEntry(identifier)
.orElseThrow(() -> NOT_FOUND_EXCEPTION.createWithContext(stringReader, identifier));
}

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return CommandSource.suggestMatching(this.registry.streamKeys().map(RegistryKey::getValue).map(Object::toString), builder);
}
}
Loading