fabric: Fully implement a registry entry argument type
This commit is contained in:
parent
98aea50d3c
commit
91b433c14b
10 changed files with 649 additions and 138 deletions
|
|
@ -739,6 +739,10 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>,
|
||||||
return this.defaultDescription;
|
return this.defaultDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final @NonNull TypeToken<T> getValueType() {
|
||||||
|
return this.valueType;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
final class MappedArgumentParser<C, I, O> implements ArgumentParser<C, O> {
|
public final class MappedArgumentParser<C, I, O> implements ArgumentParser<C, O> {
|
||||||
private final ArgumentParser<C, I> base;
|
private final ArgumentParser<C, I> base;
|
||||||
private final BiFunction<CommandContext<C>, I, ArgumentParseResult<O>> mapper;
|
private final BiFunction<CommandContext<C>, I, ArgumentParseResult<O>> mapper;
|
||||||
|
|
||||||
|
|
@ -44,6 +44,15 @@ final class MappedArgumentParser<C, I, O> implements ArgumentParser<C, O> {
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parser this one is derived from.
|
||||||
|
*
|
||||||
|
* @return the base parser
|
||||||
|
*/
|
||||||
|
public ArgumentParser<C, I> getBaseParser() {
|
||||||
|
return this.base;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull ArgumentParseResult<@NonNull O> parse(
|
public @NonNull ArgumentParseResult<@NonNull O> parse(
|
||||||
@NonNull final CommandContext<@NonNull C> commandContext,
|
@NonNull final CommandContext<@NonNull C> commandContext,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
import cloud.commandframework.captions.Caption;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
public final class FabricCaptionKeys {
|
||||||
|
|
||||||
|
private FabricCaptionKeys() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Collection<Caption> RECOGNIZED_CAPTIONS = new HashSet<>();
|
||||||
|
|
||||||
|
public static final Caption ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY = of(
|
||||||
|
"argument.parse.failure.registry_entry.unknown_entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static @NonNull Caption of(final @NonNull String key) {
|
||||||
|
final Caption caption = Caption.of(key);
|
||||||
|
RECOGNIZED_CAPTIONS.add(caption);
|
||||||
|
return caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an immutable collection containing all standard caption keys
|
||||||
|
*
|
||||||
|
* @return Immutable collection of keys
|
||||||
|
*/
|
||||||
|
public static @NonNull Collection<@NonNull Caption> getFabricCaptionKeys() {
|
||||||
|
return Collections.unmodifiableCollection(RECOGNIZED_CAPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
import cloud.commandframework.captions.SimpleCaptionRegistry;
|
||||||
|
|
||||||
|
public class FabricCaptionRegistry<C> extends SimpleCaptionRegistry<C> {
|
||||||
|
|
||||||
|
public static final String ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY = "Could not find key {id} in registry '{registry}'";
|
||||||
|
|
||||||
|
protected FabricCaptionRegistry() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.registerMessageFactory(FabricCaptionKeys.ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY,
|
||||||
|
(caption, sender) -> ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cloud.commandframework.fabric;
|
||||||
|
|
||||||
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import cloud.commandframework.keys.CloudKey;
|
||||||
|
import cloud.commandframework.keys.SimpleCloudKey;
|
||||||
|
import io.leangen.geantyref.TypeToken;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keys used in {@link CommandContext}s available within a {@link FabricCommandManager}
|
||||||
|
*/
|
||||||
|
public final class FabricCommandContextKeys {
|
||||||
|
|
||||||
|
private FabricCommandContextKeys() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final CloudKey<CommandSource> NATIVE_COMMAND_SOURCE = SimpleCloudKey.of(
|
||||||
|
"cloud:fabric_command_source",
|
||||||
|
TypeToken.get(CommandSource.class)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -33,15 +33,21 @@ import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator;
|
import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator;
|
||||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||||
|
import cloud.commandframework.fabric.argument.RegistryEntryArgument;
|
||||||
import cloud.commandframework.meta.CommandMeta;
|
import cloud.commandframework.meta.CommandMeta;
|
||||||
import cloud.commandframework.meta.SimpleCommandMeta;
|
import cloud.commandframework.meta.SimpleCommandMeta;
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import io.leangen.geantyref.GenericTypeReflector;
|
||||||
import io.leangen.geantyref.TypeToken;
|
import io.leangen.geantyref.TypeToken;
|
||||||
import net.minecraft.command.CommandSource;
|
import net.minecraft.command.CommandSource;
|
||||||
import net.minecraft.command.argument.AngleArgumentType;
|
import net.minecraft.command.argument.AngleArgumentType;
|
||||||
import net.minecraft.command.argument.BlockPredicateArgumentType;
|
import net.minecraft.command.argument.BlockPredicateArgumentType;
|
||||||
import net.minecraft.command.argument.ColorArgumentType;
|
import net.minecraft.command.argument.ColorArgumentType;
|
||||||
|
import net.minecraft.command.argument.DimensionArgumentType;
|
||||||
import net.minecraft.command.argument.EntityAnchorArgumentType;
|
import net.minecraft.command.argument.EntityAnchorArgumentType;
|
||||||
|
import net.minecraft.command.argument.EntitySummonArgumentType;
|
||||||
import net.minecraft.command.argument.IdentifierArgumentType;
|
import net.minecraft.command.argument.IdentifierArgumentType;
|
||||||
import net.minecraft.command.argument.ItemEnchantmentArgumentType;
|
import net.minecraft.command.argument.ItemEnchantmentArgumentType;
|
||||||
import net.minecraft.command.argument.ItemStackArgument;
|
import net.minecraft.command.argument.ItemStackArgument;
|
||||||
|
|
@ -57,8 +63,7 @@ import net.minecraft.command.argument.OperationArgumentType;
|
||||||
import net.minecraft.command.argument.ParticleArgumentType;
|
import net.minecraft.command.argument.ParticleArgumentType;
|
||||||
import net.minecraft.command.argument.SwizzleArgumentType;
|
import net.minecraft.command.argument.SwizzleArgumentType;
|
||||||
import net.minecraft.command.argument.UuidArgumentType;
|
import net.minecraft.command.argument.UuidArgumentType;
|
||||||
import net.minecraft.enchantment.Enchantment;
|
import net.minecraft.command.suggestion.SuggestionProviders;
|
||||||
import net.minecraft.entity.effect.StatusEffect;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.particle.ParticleEffect;
|
import net.minecraft.particle.ParticleEffect;
|
||||||
|
|
@ -68,9 +73,20 @@ import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import net.minecraft.util.registry.RegistryKey;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.lang.reflect.WildcardType;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
|
@ -89,6 +105,8 @@ import java.util.function.Supplier;
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
public abstract class FabricCommandManager<C, S extends CommandSource> extends CommandManager<C> implements BrigadierManagerHolder<C> {
|
public abstract class FabricCommandManager<C, S extends CommandSource> extends CommandManager<C> implements BrigadierManagerHolder<C> {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
private static final int MOD_PUBLIC_STATIC_FINAL = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;
|
||||||
|
|
||||||
private final Function<S, C> commandSourceMapper;
|
private final Function<S, C> commandSourceMapper;
|
||||||
private final Function<C, S> backwardsCommandSourceMapper;
|
private final Function<C, S> backwardsCommandSourceMapper;
|
||||||
|
|
@ -132,13 +150,16 @@ public abstract class FabricCommandManager<C, S extends CommandSource> extends C
|
||||||
));
|
));
|
||||||
this.brigadierManager.backwardsBrigadierSenderMapper(this.backwardsCommandSourceMapper);
|
this.brigadierManager.backwardsBrigadierSenderMapper(this.backwardsCommandSourceMapper);
|
||||||
this.registerNativeBrigadierMappings(this.brigadierManager);
|
this.registerNativeBrigadierMappings(this.brigadierManager);
|
||||||
|
this.setCaptionRegistry(new FabricCaptionRegistry<>());
|
||||||
|
this.registerCommandPreProcessor(new FabricCommandPreprocessor<>(this));
|
||||||
|
|
||||||
((FabricCommandRegistrationHandler<C, S>) this.getCommandRegistrationHandler()).initialize(this);
|
((FabricCommandRegistrationHandler<C, S>) this.getCommandRegistrationHandler()).initialize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerNativeBrigadierMappings(final CloudBrigadierManager<C, S> brigadier) {
|
private void registerNativeBrigadierMappings(final CloudBrigadierManager<C, S> brigadier) {
|
||||||
/* Cloud-native argument types */
|
/* Cloud-native argument types */
|
||||||
brigadier.registerMapping(new TypeToken<UUIDArgument.UUIDParser<C>>() {}, false, cloud -> UuidArgumentType.uuid());
|
brigadier.registerMapping(new TypeToken<UUIDArgument.UUIDParser<C>>() {}, builder -> builder.toConstant(UuidArgumentType.uuid()));
|
||||||
|
this.registerRegistryEntryMappings();
|
||||||
|
|
||||||
/* Wrapped/Constant Brigadier types, native value type */
|
/* Wrapped/Constant Brigadier types, native value type */
|
||||||
this.registerConstantNativeParserSupplier(Formatting.class, ColorArgumentType.color());
|
this.registerConstantNativeParserSupplier(Formatting.class, ColorArgumentType.color());
|
||||||
|
|
@ -151,11 +172,9 @@ public abstract class FabricCommandManager<C, S extends CommandSource> extends C
|
||||||
this.registerConstantNativeParserSupplier(AngleArgumentType.Angle.class, AngleArgumentType.angle());
|
this.registerConstantNativeParserSupplier(AngleArgumentType.Angle.class, AngleArgumentType.angle());
|
||||||
this.registerConstantNativeParserSupplier(new TypeToken<EnumSet<Direction.Axis>>() {}, SwizzleArgumentType.swizzle());
|
this.registerConstantNativeParserSupplier(new TypeToken<EnumSet<Direction.Axis>>() {}, SwizzleArgumentType.swizzle());
|
||||||
this.registerConstantNativeParserSupplier(Identifier.class, IdentifierArgumentType.identifier());
|
this.registerConstantNativeParserSupplier(Identifier.class, IdentifierArgumentType.identifier());
|
||||||
this.registerConstantNativeParserSupplier(StatusEffect.class, MobEffectArgumentType.mobEffect());
|
|
||||||
this.registerConstantNativeParserSupplier(EntityAnchorArgumentType.EntityAnchor.class, EntityAnchorArgumentType.entityAnchor());
|
this.registerConstantNativeParserSupplier(EntityAnchorArgumentType.EntityAnchor.class, EntityAnchorArgumentType.entityAnchor());
|
||||||
this.registerConstantNativeParserSupplier(NumberRange.IntRange.class, NumberRangeArgumentType.numberRange());
|
this.registerConstantNativeParserSupplier(NumberRange.IntRange.class, NumberRangeArgumentType.numberRange());
|
||||||
this.registerConstantNativeParserSupplier(NumberRange.FloatRange.class, NumberRangeArgumentType.method_30918());
|
this.registerConstantNativeParserSupplier(NumberRange.FloatRange.class, NumberRangeArgumentType.method_30918());
|
||||||
this.registerConstantNativeParserSupplier(Enchantment.class, ItemEnchantmentArgumentType.itemEnchantment());
|
|
||||||
// todo: can we add a compound argument -- MC `ItemStackArgument` is just type and tag, and count is separate
|
// todo: can we add a compound argument -- MC `ItemStackArgument` is just type and tag, and count is separate
|
||||||
this.registerConstantNativeParserSupplier(ItemStackArgument.class, ItemStackArgumentType.itemStack());
|
this.registerConstantNativeParserSupplier(ItemStackArgument.class, ItemStackArgumentType.itemStack());
|
||||||
|
|
||||||
|
|
@ -176,8 +195,6 @@ public abstract class FabricCommandManager<C, S extends CommandSource> extends C
|
||||||
this.registerConstantNativeParserSupplier(Team.class, TeamArgumentType.team());
|
this.registerConstantNativeParserSupplier(Team.class, TeamArgumentType.team());
|
||||||
this.registerConstantNativeParserSupplier(/* slot *, ItemSlotArgumentType.itemSlot());
|
this.registerConstantNativeParserSupplier(/* slot *, ItemSlotArgumentType.itemSlot());
|
||||||
this.registerConstantNativeParserSupplier(CommandFunction.class, FunctionArgumentType.function());
|
this.registerConstantNativeParserSupplier(CommandFunction.class, FunctionArgumentType.function());
|
||||||
this.registerConstantNativeParserSupplier(EntityType.class, EntitySummonArgumentType.entitySummon()); // entity summon
|
|
||||||
this.registerConstantNativeParserSupplier(ServerWorld.class, DimensionArgumentType.dimension());
|
|
||||||
this.registerConstantNativeParserSupplier(/* time representation in ticks *, TimeArgumentType.time());*/
|
this.registerConstantNativeParserSupplier(/* time representation in ticks *, TimeArgumentType.time());*/
|
||||||
|
|
||||||
/* Wrapped brigadier requiring parameters */
|
/* Wrapped brigadier requiring parameters */
|
||||||
|
|
@ -185,6 +202,91 @@ public abstract class FabricCommandManager<C, S extends CommandSource> extends C
|
||||||
// entity argument type: single or multiple, players or any entity -- returns EntitySelector, but do we want that?
|
// entity argument type: single or multiple, players or any entity -- returns EntitySelector, but do we want that?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
private void registerRegistryEntryMappings() {
|
||||||
|
this.brigadierManager.registerMapping(new TypeToken<RegistryEntryArgument.RegistryEntryParser<C, ?>>() {},
|
||||||
|
builder -> builder.to(argument -> {
|
||||||
|
/* several registries have specialized argument types, so let's use those where possible */
|
||||||
|
final RegistryKey<? extends Registry<?>> registry = argument.getRegistry();
|
||||||
|
if (registry.equals(Registry.ENTITY_TYPE_KEY)) {
|
||||||
|
return EntitySummonArgumentType.entitySummon();
|
||||||
|
} else if (registry.equals(Registry.ENCHANTMENT_KEY)) {
|
||||||
|
return ItemEnchantmentArgumentType.itemEnchantment();
|
||||||
|
} else if (registry.equals(Registry.MOB_EFFECT_KEY)) { // yarn wai
|
||||||
|
return MobEffectArgumentType.mobEffect();
|
||||||
|
} else if (registry.equals(Registry.DIMENSION)) {
|
||||||
|
return DimensionArgumentType.dimension();
|
||||||
|
}
|
||||||
|
return IdentifierArgumentType.identifier();
|
||||||
|
}
|
||||||
|
).suggestedBy((argument, useCloud) -> {
|
||||||
|
/* A few other registries have client-side suggestion providers but no argument type */
|
||||||
|
/* Type parameters are messed up here for some reason */
|
||||||
|
final RegistryKey<? extends Registry<?>> registry = argument.getRegistry();
|
||||||
|
if (registry.equals(Registry.SOUND_EVENT_KEY)) {
|
||||||
|
return (SuggestionProvider<S>) SuggestionProviders.AVAILABLE_SOUNDS;
|
||||||
|
} else if (registry.equals(Registry.BIOME_KEY)) {
|
||||||
|
return (SuggestionProvider<S>) SuggestionProviders.ALL_BIOMES;
|
||||||
|
} else if (registry.equals(Registry.ENTITY_TYPE_KEY)
|
||||||
|
|| registry.equals(Registry.ENCHANTMENT_KEY)
|
||||||
|
|| registry.equals(Registry.MOB_EFFECT_KEY)
|
||||||
|
|| registry.equals(Registry.DIMENSION)) {
|
||||||
|
return null; /* for types with their own argument type, use Brigadier */
|
||||||
|
}
|
||||||
|
return useCloud; /* use cloud suggestions for anything else */
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Find all fields of RegistryKey<? extends Registry<?>> and register those */
|
||||||
|
/* This only works for vanilla registries really, we'll have to do other things for non-vanilla ones */
|
||||||
|
final Set<Class<?>> seenClasses = new HashSet<>();
|
||||||
|
/* Some registries have types that are too generic... we'll skip those for now.
|
||||||
|
* Eventually, these could be resolved by using ParserParameters in some way? */
|
||||||
|
seenClasses.add(Identifier.class);
|
||||||
|
seenClasses.add(Codec.class);
|
||||||
|
for (final Field field : Registry.class.getDeclaredFields()) {
|
||||||
|
if ((field.getModifiers() & MOD_PUBLIC_STATIC_FINAL) != MOD_PUBLIC_STATIC_FINAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!field.getType().equals(RegistryKey.class)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Type generic = field.getGenericType(); /* RegistryKey<? extends Registry<?>> */
|
||||||
|
if (!(generic instanceof ParameterizedType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type registryType = ((ParameterizedType) generic).getActualTypeArguments()[0];
|
||||||
|
while (registryType instanceof WildcardType) {
|
||||||
|
registryType = ((WildcardType) registryType).getUpperBounds()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(registryType instanceof ParameterizedType)) { /* expected: Registry<V> */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final RegistryKey<?> key;
|
||||||
|
try {
|
||||||
|
key = (RegistryKey<?>) field.get(null);
|
||||||
|
} catch (final IllegalAccessException ex) {
|
||||||
|
LOGGER.warn("Failed to access value of registry key in field {} of type {}", field.getName(), generic, ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Type valueType = ((ParameterizedType) registryType).getActualTypeArguments()[0];
|
||||||
|
if (seenClasses.contains(GenericTypeReflector.erase(valueType))) {
|
||||||
|
LOGGER.debug("Encountered duplicate type in registry {}: type {}", key, valueType);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seenClasses.add(GenericTypeReflector.erase(valueType));
|
||||||
|
|
||||||
|
/* and now, finally, we can register */
|
||||||
|
this.getParserRegistry().registerParserSupplier(TypeToken.get(valueType),
|
||||||
|
params -> new RegistryEntryArgument.RegistryEntryParser(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a parser supplier for a brigadier type that has no options and whose output can be directly used.
|
* Register a parser supplier for a brigadier type that has no options and whose output can be directly used.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext;
|
||||||
|
import cloud.commandframework.execution.preprocessor.CommandPreprocessor;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
final class FabricCommandPreprocessor<C> implements CommandPreprocessor<C> {
|
||||||
|
|
||||||
|
private final FabricCommandManager<C, ?> manager;
|
||||||
|
|
||||||
|
FabricCommandPreprocessor(final FabricCommandManager<C, ?> manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(@NonNull final CommandPreprocessingContext<C> context) {
|
||||||
|
context.getCommandContext().store(
|
||||||
|
FabricCommandContextKeys.NATIVE_COMMAND_SOURCE,
|
||||||
|
this.manager.getBackwardsCommandSourceMapper().apply(context.getCommandContext().getSender())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
|
||||||
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
|
|
||||||
import cloud.commandframework.context.CommandContext;
|
|
||||||
import net.minecraft.command.argument.ItemEnchantmentArgumentType;
|
|
||||||
import net.minecraft.enchantment.Enchantment;
|
|
||||||
import net.minecraft.util.registry.Registry;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An argument parsing enchantment identifier from the {@link Registry#ENCHANTMENT enchantments registry}.
|
|
||||||
*
|
|
||||||
* @param <C> the sender type
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public final class EnchantmentArgument<C> extends CommandArgument<C, Enchantment> {
|
|
||||||
|
|
||||||
EnchantmentArgument(
|
|
||||||
final boolean required,
|
|
||||||
final @NonNull String name,
|
|
||||||
final @NonNull String defaultValue,
|
|
||||||
final @Nullable BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
required,
|
|
||||||
name,
|
|
||||||
new WrappedBrigadierParser<>(ItemEnchantmentArgumentType.itemEnchantment()),
|
|
||||||
defaultValue,
|
|
||||||
Enchantment.class,
|
|
||||||
suggestionsProvider
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new builder.
|
|
||||||
*
|
|
||||||
* @param name Name of the argument
|
|
||||||
* @param <C> Command sender type
|
|
||||||
* @return Created builder
|
|
||||||
*/
|
|
||||||
public static <C> EnchantmentArgument.@NonNull Builder<C> newBuilder(final @NonNull String name) {
|
|
||||||
return new EnchantmentArgument.Builder<>(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new required command argument.
|
|
||||||
*
|
|
||||||
* @param name Component name
|
|
||||||
* @param <C> Command sender type
|
|
||||||
* @return Created argument
|
|
||||||
*/
|
|
||||||
public static <C> @NonNull EnchantmentArgument<C> of(final @NonNull String name) {
|
|
||||||
return EnchantmentArgument.<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 EnchantmentArgument<C> optional(final @NonNull String name) {
|
|
||||||
return EnchantmentArgument.<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 EnchantmentArgument<C> optional(
|
|
||||||
final @NonNull String name,
|
|
||||||
final Enchantment defaultValue
|
|
||||||
) {
|
|
||||||
return EnchantmentArgument.<C>newBuilder(name).asOptionalWithDefault(Registry.ENCHANTMENT.getId(defaultValue).toString()).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final class Builder<C> extends TypedBuilder<C, Enchantment, Builder<C>> {
|
|
||||||
|
|
||||||
Builder(final @NonNull String name) {
|
|
||||||
super(Enchantment.class, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a new criterion argument
|
|
||||||
*
|
|
||||||
* @return Constructed argument
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public @NonNull EnchantmentArgument<C> build() {
|
|
||||||
return new EnchantmentArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(), this.getSuggestionsProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
public class FabricArgumentParsers {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,327 @@
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
|
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||||
|
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
|
import cloud.commandframework.captions.CaptionVariable;
|
||||||
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
|
||||||
|
import cloud.commandframework.exceptions.parsing.ParserException;
|
||||||
|
import cloud.commandframework.fabric.FabricCaptionKeys;
|
||||||
|
import cloud.commandframework.fabric.FabricCommandContextKeys;
|
||||||
|
import com.mojang.brigadier.StringReader;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import io.leangen.geantyref.TypeToken;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import net.minecraft.util.registry.RegistryKey;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from a registry.
|
||||||
|
*
|
||||||
|
* <p>Both static and dynamic registries are supported.</p>
|
||||||
|
*
|
||||||
|
* @param <C> the command sender type
|
||||||
|
* @param <V> the registry entry type
|
||||||
|
*/
|
||||||
|
public class RegistryEntryArgument<C, V> extends CommandArgument<C, V> {
|
||||||
|
private static final String NAMESPACE_MINECRAFT = "minecraft";
|
||||||
|
|
||||||
|
RegistryEntryArgument(
|
||||||
|
final boolean required,
|
||||||
|
final @NonNull String name,
|
||||||
|
final @NonNull RegistryKey<? extends Registry<V>> registry,
|
||||||
|
final @NonNull String defaultValue,
|
||||||
|
final @NonNull TypeToken<V> valueType,
|
||||||
|
final @Nullable BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider
|
||||||
|
) {
|
||||||
|
super(required, name, new RegistryEntryParser<>(registry), defaultValue, valueType, suggestionsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new builder.
|
||||||
|
*
|
||||||
|
* @param name Name of the argument
|
||||||
|
* @param type The type of registry entry
|
||||||
|
* @param registry A key for the registry to get values from
|
||||||
|
* @param <C> Command sender type
|
||||||
|
* @param <V> Registry entry type
|
||||||
|
* @return Created builder
|
||||||
|
*/
|
||||||
|
public static <C, V> RegistryEntryArgument.@NonNull Builder<C, V> newBuilder(
|
||||||
|
final @NonNull String name,
|
||||||
|
final @NonNull Class<V> type,
|
||||||
|
final @NonNull RegistryKey<? extends Registry<V>> registry) {
|
||||||
|
return new RegistryEntryArgument.Builder<>(registry, type, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new builder.
|
||||||
|
*
|
||||||
|
* @param name Name of the argument
|
||||||
|
* @param type The type of registry entry
|
||||||
|
* @param registry A key for the registry to get values from
|
||||||
|
* @param <C> Command sender type
|
||||||
|
* @param <V> Registry entry type
|
||||||
|
* @return Created builder
|
||||||
|
*/
|
||||||
|
public static <C, V> RegistryEntryArgument.@NonNull Builder<C, V> newBuilder(
|
||||||
|
final @NonNull String name,
|
||||||
|
final @NonNull TypeToken<V> type,
|
||||||
|
final @NonNull RegistryKey<? extends Registry<V>> registry) {
|
||||||
|
return new RegistryEntryArgument.Builder<>(registry, type, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new required command argument.
|
||||||
|
*
|
||||||
|
* @param name Argument name
|
||||||
|
* @param type The type of registry entry
|
||||||
|
* @param registry A key for the registry to get values from
|
||||||
|
* @param <C> Command sender type
|
||||||
|
* @param <V> Registry entry type
|
||||||
|
* @return Created argument
|
||||||
|
*/
|
||||||
|
public static <C, V> @NonNull RegistryEntryArgument<C, V> of(
|
||||||
|
final @NonNull String name,
|
||||||
|
final @NonNull Class<V> type,
|
||||||
|
final @NonNull RegistryKey<? extends Registry<V>> registry
|
||||||
|
) {
|
||||||
|
return RegistryEntryArgument.<C, V>newBuilder(name, type, registry).asRequired().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new optional command argument
|
||||||
|
*
|
||||||
|
* @param name Argument name
|
||||||
|
* @param type The type of registry entry
|
||||||
|
* @param registry A key for the registry to get values from
|
||||||
|
* @param <C> Command sender type
|
||||||
|
* @param <V> Registry entry type
|
||||||
|
* @return Created argument
|
||||||
|
*/
|
||||||
|
public static <C, V> @NonNull RegistryEntryArgument<C, V> optional(
|
||||||
|
final @NonNull String name,
|
||||||
|
final @NonNull Class<V> type,
|
||||||
|
final @NonNull RegistryKey<? extends Registry<V>> registry
|
||||||
|
) {
|
||||||
|
return RegistryEntryArgument.<C, V>newBuilder(name, type, registry).asOptional().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new optional command argument with a default value
|
||||||
|
*
|
||||||
|
* @param name Argument name
|
||||||
|
* @param type The type of registry entry
|
||||||
|
* @param registry A key for the registry to get values from
|
||||||
|
* @param defaultValue Default value
|
||||||
|
* @param <C> Command sender type
|
||||||
|
* @param <V> Registry entry type
|
||||||
|
* @return Created argument
|
||||||
|
*/
|
||||||
|
public static <C, V> @NonNull RegistryEntryArgument<C, V> optional(
|
||||||
|
final @NonNull String name,
|
||||||
|
final @NonNull Class<V> type,
|
||||||
|
final @NonNull RegistryKey<? extends Registry<V>> registry,
|
||||||
|
final @NonNull RegistryKey<V> defaultValue
|
||||||
|
) {
|
||||||
|
return RegistryEntryArgument.<C, V>newBuilder(name, type, registry)
|
||||||
|
.asOptionalWithDefault(defaultValue.getValue().toString())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parser for values stored in a {@link Registry}
|
||||||
|
*
|
||||||
|
* @param <C> Command sender type
|
||||||
|
* @param <V> Registry entry type
|
||||||
|
*/
|
||||||
|
public static final class RegistryEntryParser<C, V> implements ArgumentParser<C, V> {
|
||||||
|
private final RegistryKey<? extends Registry<V>> registryIdent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new parser for registry entries.
|
||||||
|
*
|
||||||
|
* @param registryIdent the registry identifier
|
||||||
|
*/
|
||||||
|
public RegistryEntryParser(final RegistryKey<? extends Registry<V>> registryIdent) {
|
||||||
|
this.registryIdent = requireNonNull(registryIdent, "registryIdent");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull ArgumentParseResult<@NonNull V> parse(
|
||||||
|
@NonNull final CommandContext<@NonNull C> commandContext,
|
||||||
|
@NonNull final Queue<@NonNull String> inputQueue
|
||||||
|
) {
|
||||||
|
final String possibleIdentifier = inputQueue.peek();
|
||||||
|
if (possibleIdentifier == null) {
|
||||||
|
return ArgumentParseResult.failure(new NoInputProvidedException(
|
||||||
|
RegistryEntryArgument.class,
|
||||||
|
commandContext
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Identifier key;
|
||||||
|
try {
|
||||||
|
key = Identifier.fromCommandInput(new StringReader(possibleIdentifier));
|
||||||
|
} catch (final CommandSyntaxException ex) {
|
||||||
|
return ArgumentParseResult.failure(ex);
|
||||||
|
}
|
||||||
|
inputQueue.poll();
|
||||||
|
|
||||||
|
final Registry<V> registry = this.getRegistry(commandContext);
|
||||||
|
if (registry == null) {
|
||||||
|
return ArgumentParseResult.failure(new IllegalArgumentException("Unknown registry " + this.registryIdent));
|
||||||
|
}
|
||||||
|
|
||||||
|
final V entry = registry.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
return ArgumentParseResult.failure(new UnknownEntryException(commandContext, key, this.registryIdent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ArgumentParseResult.success(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Registry<V> getRegistry(final CommandContext<C> ctx) {
|
||||||
|
final CommandSource reverseMapped = ctx.get(FabricCommandContextKeys.NATIVE_COMMAND_SOURCE);
|
||||||
|
// First try dynamic registries (for things loaded from data-packs)
|
||||||
|
Registry<V> registry = reverseMapped.getRegistryManager().getOptional(this.registryIdent).orElse(null);
|
||||||
|
if (registry == null) {
|
||||||
|
// And then static registries
|
||||||
|
registry = (Registry<V>) Registry.REGISTRIES.get(this.registryIdent.getValue());
|
||||||
|
}
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull List<@NonNull String> suggestions(
|
||||||
|
final @NonNull CommandContext<C> commandContext,
|
||||||
|
final @NonNull String input
|
||||||
|
) {
|
||||||
|
final Set<Identifier> ids = this.getRegistry(commandContext).getIds();
|
||||||
|
final List<String> results = new ArrayList<>(ids.size());
|
||||||
|
for (final Identifier entry : ids) {
|
||||||
|
if (entry.getNamespace().equals(NAMESPACE_MINECRAFT)) {
|
||||||
|
results.add(entry.getPath());
|
||||||
|
}
|
||||||
|
results.add(entry.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isContextFree() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the registry associated with this parser
|
||||||
|
* @return the registry
|
||||||
|
*/
|
||||||
|
public RegistryKey<? extends Registry<?>> getRegistry() {
|
||||||
|
return this.registryIdent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder for registry entry arguments.
|
||||||
|
*
|
||||||
|
* @param <C> The sender type
|
||||||
|
* @param <V> The registry value type
|
||||||
|
*/
|
||||||
|
public static final class Builder<C, V> extends CommandArgument.TypedBuilder<C, V, Builder<C, V>> {
|
||||||
|
private final RegistryKey<? extends Registry<V>> registryIdent;
|
||||||
|
|
||||||
|
Builder(
|
||||||
|
final RegistryKey<? extends Registry<V>> key,
|
||||||
|
final @NonNull Class<V> valueType,
|
||||||
|
final @NonNull String name
|
||||||
|
) {
|
||||||
|
super(valueType, name);
|
||||||
|
this.registryIdent = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder(
|
||||||
|
final RegistryKey<? extends Registry<V>> key,
|
||||||
|
final @NonNull TypeToken<V> valueType,
|
||||||
|
final @NonNull String name
|
||||||
|
) {
|
||||||
|
super(valueType, name);
|
||||||
|
this.registryIdent = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull RegistryEntryArgument<@NonNull C, @NonNull V> build() {
|
||||||
|
return new RegistryEntryArgument<>(
|
||||||
|
this.isRequired(),
|
||||||
|
this.getName(),
|
||||||
|
this.registryIdent,
|
||||||
|
this.getDefaultValue(),
|
||||||
|
this.getValueType(),
|
||||||
|
this.getSuggestionsProvider()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception thrown when an entry in a registry could not be found.
|
||||||
|
*/
|
||||||
|
private static final class UnknownEntryException extends ParserException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7694424294461849903L;
|
||||||
|
|
||||||
|
UnknownEntryException(
|
||||||
|
final CommandContext<?> context,
|
||||||
|
final Identifier key,
|
||||||
|
final RegistryKey<? extends Registry<?>> registry
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
RegistryEntryArgument.class,
|
||||||
|
context,
|
||||||
|
FabricCaptionKeys.ARGUMENT_PARSE_FAILURE_REGISTRY_ENTRY_UNKNOWN_ENTRY,
|
||||||
|
CaptionVariable.of("id", key.toString()),
|
||||||
|
CaptionVariable.of("registry", registry.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue