package net.minecraft.commands.synchronization; import com.google.common.collect.Maps; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import java.util.Map; import java.util.concurrent.CompletableFuture; import net.minecraft.Util; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.EntityType; public class SuggestionProviders { private static final Map> PROVIDERS_BY_NAME = Maps.>newHashMap(); private static final ResourceLocation DEFAULT_NAME = ResourceLocation.withDefaultNamespace("ask_server"); public static final SuggestionProvider ASK_SERVER = register( DEFAULT_NAME, (commandContext, suggestionsBuilder) -> commandContext.getSource().customSuggestion(commandContext) ); public static final SuggestionProvider AVAILABLE_SOUNDS = register( ResourceLocation.withDefaultNamespace("available_sounds"), (commandContext, suggestionsBuilder) -> SharedSuggestionProvider.suggestResource(commandContext.getSource().getAvailableSounds(), suggestionsBuilder) ); public static final SuggestionProvider SUMMONABLE_ENTITIES = register( ResourceLocation.withDefaultNamespace("summonable_entities"), (commandContext, suggestionsBuilder) -> SharedSuggestionProvider.suggestResource( BuiltInRegistries.ENTITY_TYPE.stream().filter(entityType -> entityType.isEnabled(commandContext.getSource().enabledFeatures()) && entityType.canSummon()), suggestionsBuilder, EntityType::getKey, entityType -> Component.translatable(Util.makeDescriptionId("entity", EntityType.getKey(entityType))) ) ); public static SuggestionProvider register(ResourceLocation name, SuggestionProvider provider) { if (PROVIDERS_BY_NAME.containsKey(name)) { throw new IllegalArgumentException("A command suggestion provider is already registered with the name " + name); } else { PROVIDERS_BY_NAME.put(name, provider); return new SuggestionProviders.Wrapper(name, provider); } } public static SuggestionProvider getProvider(ResourceLocation name) { return (SuggestionProvider)PROVIDERS_BY_NAME.getOrDefault(name, ASK_SERVER); } /** * Gets the ID for the given provider. If the provider is not a wrapped one created via {@link #register}, then it returns {@link #ASK_SERVER_ID} instead, as there is no known ID but ASK_SERVER always works. */ public static ResourceLocation getName(SuggestionProvider provider) { return provider instanceof SuggestionProviders.Wrapper ? ((SuggestionProviders.Wrapper)provider).name : DEFAULT_NAME; } /** * Checks to make sure that the given suggestion provider is a wrapped one that was created via {@link #register}. If not, returns {@link #ASK_SERVER}. Needed because custom providers don't have a known ID to send to the client, but ASK_SERVER always works. */ public static SuggestionProvider safelySwap(SuggestionProvider provider) { return provider instanceof SuggestionProviders.Wrapper ? provider : ASK_SERVER; } protected static class Wrapper implements SuggestionProvider { private final SuggestionProvider delegate; final ResourceLocation name; public Wrapper(ResourceLocation name, SuggestionProvider delegate) { this.delegate = delegate; this.name = name; } @Override public CompletableFuture getSuggestions(CommandContext commandContext, SuggestionsBuilder suggestionsBuilder) throws CommandSyntaxException { return this.delegate.getSuggestions(commandContext, suggestionsBuilder); } } }