package net.minecraft.commands.arguments; import com.google.gson.JsonObject; 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 java.util.Arrays; import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.SharedSuggestionProvider.ElementSuggestionType; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.core.Registry; import net.minecraft.core.Holder.Reference; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; public class ResourceKeyArgument implements ArgumentType> { private static final Collection EXAMPLES = Arrays.asList("foo", "foo:bar", "012"); private static final DynamicCommandExceptionType ERROR_INVALID_FEATURE = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.place.feature.invalid", object) ); private static final DynamicCommandExceptionType ERROR_INVALID_STRUCTURE = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.place.structure.invalid", object) ); private static final DynamicCommandExceptionType ERROR_INVALID_TEMPLATE_POOL = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.place.jigsaw.invalid", object) ); private static final DynamicCommandExceptionType ERROR_INVALID_RECIPE = new DynamicCommandExceptionType( object -> Component.translatableEscape("recipe.notFound", object) ); private static final DynamicCommandExceptionType ERROR_INVALID_ADVANCEMENT = new DynamicCommandExceptionType( object -> Component.translatableEscape("advancement.advancementNotFound", object) ); final ResourceKey> registryKey; public ResourceKeyArgument(ResourceKey> registryKey) { this.registryKey = registryKey; } public static ResourceKeyArgument key(ResourceKey> registryKey) { return new ResourceKeyArgument<>(registryKey); } public static ResourceKey getRegistryKey( CommandContext context, String argument, ResourceKey> registryKey, DynamicCommandExceptionType exception ) throws CommandSyntaxException { ResourceKey resourceKey = context.getArgument(argument, ResourceKey.class); Optional> optional = resourceKey.cast(registryKey); return (ResourceKey)optional.orElseThrow(() -> exception.create(resourceKey.location())); } private static Registry getRegistry(CommandContext context, ResourceKey> registryKey) { return context.getSource().getServer().registryAccess().lookupOrThrow(registryKey); } private static Reference resolveKey( CommandContext context, String argument, ResourceKey> registryKey, DynamicCommandExceptionType exception ) throws CommandSyntaxException { ResourceKey resourceKey = getRegistryKey(context, argument, registryKey, exception); return (Reference)getRegistry(context, registryKey).get(resourceKey).orElseThrow(() -> exception.create(resourceKey.location())); } public static Reference> getConfiguredFeature(CommandContext context, String argument) throws CommandSyntaxException { return resolveKey(context, argument, Registries.CONFIGURED_FEATURE, ERROR_INVALID_FEATURE); } public static Reference getStructure(CommandContext context, String argument) throws CommandSyntaxException { return resolveKey(context, argument, Registries.STRUCTURE, ERROR_INVALID_STRUCTURE); } public static Reference getStructureTemplatePool(CommandContext context, String argument) throws CommandSyntaxException { return resolveKey(context, argument, Registries.TEMPLATE_POOL, ERROR_INVALID_TEMPLATE_POOL); } public static RecipeHolder getRecipe(CommandContext context, String argument) throws CommandSyntaxException { RecipeManager recipeManager = context.getSource().getServer().getRecipeManager(); ResourceKey> resourceKey = getRegistryKey(context, argument, Registries.RECIPE, ERROR_INVALID_RECIPE); return (RecipeHolder)recipeManager.byKey(resourceKey).orElseThrow(() -> ERROR_INVALID_RECIPE.create(resourceKey.location())); } public static AdvancementHolder getAdvancement(CommandContext context, String argument) throws CommandSyntaxException { ResourceKey resourceKey = getRegistryKey(context, argument, Registries.ADVANCEMENT, ERROR_INVALID_ADVANCEMENT); AdvancementHolder advancementHolder = context.getSource().getServer().getAdvancements().get(resourceKey.location()); if (advancementHolder == null) { throw ERROR_INVALID_ADVANCEMENT.create(resourceKey.location()); } else { return advancementHolder; } } public ResourceKey parse(StringReader reader) throws CommandSyntaxException { ResourceLocation resourceLocation = ResourceLocation.read(reader); return ResourceKey.create(this.registryKey, resourceLocation); } @Override public CompletableFuture listSuggestions(CommandContext commandContext, SuggestionsBuilder suggestionsBuilder) { return commandContext.getSource() instanceof SharedSuggestionProvider sharedSuggestionProvider ? sharedSuggestionProvider.suggestRegistryElements(this.registryKey, ElementSuggestionType.ELEMENTS, suggestionsBuilder, commandContext) : suggestionsBuilder.buildFuture(); } @Override public Collection getExamples() { return EXAMPLES; } public static class Info implements ArgumentTypeInfo, ResourceKeyArgument.Info.Template> { public void serializeToNetwork(ResourceKeyArgument.Info.Template template, FriendlyByteBuf friendlyByteBuf) { friendlyByteBuf.writeResourceKey(template.registryKey); } public ResourceKeyArgument.Info.Template deserializeFromNetwork(FriendlyByteBuf friendlyByteBuf) { return new net.minecraft.commands.arguments.ResourceKeyArgument.Info.Template(this, friendlyByteBuf.readRegistryKey()); } public void serializeToJson(ResourceKeyArgument.Info.Template template, JsonObject jsonObject) { jsonObject.addProperty("registry", template.registryKey.location().toString()); } public ResourceKeyArgument.Info.Template unpack(ResourceKeyArgument resourceKeyArgument) { return new net.minecraft.commands.arguments.ResourceKeyArgument.Info.Template(this, resourceKeyArgument.registryKey); } } }