aboutsummaryrefslogtreecommitdiffhomepage
path: root/test-plugin
diff options
context:
space:
mode:
authorOwen1212055 <[email protected]>2024-05-11 16:30:30 -0400
committerOwen1212055 <[email protected]>2024-05-11 16:30:30 -0400
commit567cc3f4b35e7a7fafb0dd4c713ce0624607e24d (patch)
tree41fb1377d30dc639204440db44d0cea3a338b028 /test-plugin
parent8a5ea7e5cf6320eb1ac79af93a1930f66ed0ad1a (diff)
downloadPaper-567cc3f4b35e7a7fafb0dd4c713ce0624607e24d.tar.gz
Paper-567cc3f4b35e7a7fafb0dd4c713ce0624607e24d.zip
Brigadier Command Support (#8235)
Adds the ability for plugins to register their own brigadier commands --------- Co-authored-by: Jake Potrebic <[email protected]> Co-authored-by: Jason Penilla <[email protected]> Co-authored-by: Bjarne Koll <[email protected]>
Diffstat (limited to 'test-plugin')
-rw-r--r--test-plugin/build.gradle.kts1
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java3
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java1
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/brigtests/Registration.java166
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ComponentCommandExceptionType.java25
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ExampleAdminCommand.java154
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamType.java9
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamTypeArgument.java47
-rw-r--r--test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/MaterialArgumentType.java88
9 files changed, 493 insertions, 1 deletions
diff --git a/test-plugin/build.gradle.kts b/test-plugin/build.gradle.kts
index 3edf55f288..9f7d9da599 100644
--- a/test-plugin/build.gradle.kts
+++ b/test-plugin/build.gradle.kts
@@ -2,7 +2,6 @@ version = "1.0.0-SNAPSHOT"
dependencies {
compileOnly(project(":paper-api"))
- compileOnly(project(":paper-mojangapi"))
}
tasks.processResources {
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java
index 4e68423bb7..671c37fa40 100644
--- a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java
+++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java
@@ -8,5 +8,8 @@ public final class TestPlugin extends JavaPlugin implements Listener {
@Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
+
+ // io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this);
}
+
}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java
index e978b15f97..fe2b287b25 100644
--- a/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java
+++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java
@@ -8,6 +8,7 @@ public class TestPluginBootstrap implements PluginBootstrap {
@Override
public void bootstrap(@NotNull BootstrapContext context) {
+ // io.papermc.testplugin.brigtests.Registration.registerViaBootstrap(context);
}
}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/brigtests/Registration.java b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/Registration.java
new file mode 100644
index 0000000000..cd24899f34
--- /dev/null
+++ b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/Registration.java
@@ -0,0 +1,166 @@
+package io.papermc.testplugin.brigtests;
+
+import com.mojang.brigadier.Command;
+import io.papermc.paper.command.brigadier.BasicCommand;
+import io.papermc.paper.command.brigadier.CommandSourceStack;
+import io.papermc.paper.command.brigadier.Commands;
+import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
+import io.papermc.paper.command.brigadier.argument.range.DoubleRangeProvider;
+import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
+import io.papermc.testplugin.brigtests.example.ExampleAdminCommand;
+import io.papermc.testplugin.brigtests.example.MaterialArgumentType;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.defaults.BukkitCommand;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.NotNull;
+
+public final class Registration {
+
+ private Registration() {
+ }
+
+ public static void registerViaOnEnable(final JavaPlugin plugin) {
+ registerLegacyCommands(plugin);
+ registerViaLifecycleEvents(plugin);
+ }
+
+ private static void registerViaLifecycleEvents(final JavaPlugin plugin) {
+ final LifecycleEventManager<Plugin> lifecycleManager = plugin.getLifecycleManager();
+ lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
+ final Commands commands = event.registrar();
+ // ensure plugin commands override
+ commands.register(Commands.literal("tag")
+ .executes(ctx -> {
+ ctx.getSource().getSender().sendPlainMessage("overriden command");
+ return Command.SINGLE_SUCCESS;
+ })
+ .build(),
+ null,
+ Collections.emptyList()
+ );
+ });
+
+ lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(event -> {
+ final Commands commands = event.registrar();
+ commands.register(plugin.getPluginMeta(), Commands.literal("root_command")
+ .then(Commands.literal("sub_command")
+ .requires(source -> source.getSender().hasPermission("testplugin.test"))
+ .executes(ctx -> {
+ ctx.getSource().getSender().sendPlainMessage("root_command sub_command");
+ return Command.SINGLE_SUCCESS;
+ })).build(),
+ null,
+ Collections.emptyList()
+ );
+
+ commands.register(plugin.getPluginMeta(), "example", "test", Collections.emptyList(), new BasicCommand() {
+ @Override
+ public void execute(@NotNull final CommandSourceStack commandSourceStack, final @NotNull String[] args) {
+ System.out.println(Arrays.toString(args));
+ }
+
+ @Override
+ public @NotNull Collection<String> suggest(final @NotNull CommandSourceStack commandSourceStack, final @NotNull String[] args) {
+ System.out.println(Arrays.toString(args));
+ return List.of("apple", "banana");
+ }
+ });
+
+
+ commands.register(plugin.getPluginMeta(), Commands.literal("water")
+ .requires(source -> {
+ System.out.println("isInWater check");
+ return source.getExecutor().isInWater();
+ })
+ .executes(ctx -> {
+ ctx.getSource().getExecutor().sendMessage("You are in water!");
+ return Command.SINGLE_SUCCESS;
+ }).then(Commands.literal("lava")
+ .requires(source -> {
+ System.out.println("isInLava check");
+ if (source.getExecutor() != null) {
+ return source.getExecutor().isInLava();
+ }
+ return true;
+ })
+ .executes(ctx -> {
+ ctx.getSource().getExecutor().sendMessage("You are in lava!");
+ return Command.SINGLE_SUCCESS;
+ })).build(),
+ null,
+ Collections.emptyList());
+
+
+ ExampleAdminCommand.register(plugin, commands);
+ }).priority(10));
+ }
+
+ private static void registerLegacyCommands(final JavaPlugin plugin) {
+ plugin.getServer().getCommandMap().register("fallback", new BukkitCommand("hi", "cool hi command", "<>", List.of("hialias")) {
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ sender.sendMessage("hi");
+ return true;
+ }
+ });
+ plugin.getServer().getCommandMap().register("fallback", new BukkitCommand("cooler-command", "cool hi command", "<>", List.of("cooler-command-alias")) {
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ sender.sendMessage("hi");
+ return true;
+ }
+ });
+ plugin.getServer().getCommandMap().getKnownCommands().values().removeIf((command) -> {
+ return command.getName().equals("hi");
+ });
+ }
+
+ public static void registerViaBootstrap(final BootstrapContext context) {
+ final LifecycleEventManager<BootstrapContext> lifecycleManager = context.getLifecycleManager();
+ lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
+ final Commands commands = event.registrar();
+ commands.register(Commands.literal("material")
+ .then(Commands.literal("item")
+ .then(Commands.argument("mat", MaterialArgumentType.item())
+ .executes(ctx -> {
+ ctx.getSource().getSender().sendPlainMessage(ctx.getArgument("mat", Material.class).name());
+ return Command.SINGLE_SUCCESS;
+ })
+ )
+ ).then(Commands.literal("block")
+ .then(Commands.argument("mat", MaterialArgumentType.block())
+ .executes(ctx -> {
+ ctx.getSource().getSender().sendPlainMessage(ctx.getArgument("mat", Material.class).name());
+ return Command.SINGLE_SUCCESS;
+ })
+ )
+ )
+ .build(),
+ null,
+ Collections.emptyList()
+ );
+ });
+
+ lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(event -> {
+ final Commands commands = event.registrar();
+ commands.register(Commands.literal("heya")
+ .then(Commands.argument("range", ArgumentTypes.doubleRange())
+ .executes((ct) -> {
+ ct.getSource().getSender().sendPlainMessage(ct.getArgument("range", DoubleRangeProvider.class).range().toString());
+ return 1;
+ })
+ ).build(),
+ null,
+ Collections.emptyList()
+ );
+ }).priority(10));
+ }
+}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ComponentCommandExceptionType.java b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ComponentCommandExceptionType.java
new file mode 100644
index 0000000000..7b8d9db790
--- /dev/null
+++ b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ComponentCommandExceptionType.java
@@ -0,0 +1,25 @@
+package io.papermc.testplugin.brigtests.example;
+
+import com.mojang.brigadier.ImmutableStringReader;
+import com.mojang.brigadier.Message;
+import com.mojang.brigadier.exceptions.CommandExceptionType;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import io.papermc.paper.command.brigadier.MessageComponentSerializer;
+import net.kyori.adventure.text.Component;
+
+public class ComponentCommandExceptionType implements CommandExceptionType {
+
+ private final Message message;
+
+ public ComponentCommandExceptionType(final Component message) {
+ this.message = MessageComponentSerializer.message().serialize(message);
+ }
+
+ public CommandSyntaxException create() {
+ return new CommandSyntaxException(this, this.message);
+ }
+
+ public CommandSyntaxException createWithContext(final ImmutableStringReader reader) {
+ return new CommandSyntaxException(this, this.message, reader.getString(), reader.getCursor());
+ }
+}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ExampleAdminCommand.java b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ExampleAdminCommand.java
new file mode 100644
index 0000000000..83f1ebb93e
--- /dev/null
+++ b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/ExampleAdminCommand.java
@@ -0,0 +1,154 @@
+package io.papermc.testplugin.brigtests.example;
+
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import io.papermc.paper.command.brigadier.CommandSourceStack;
+import io.papermc.paper.command.brigadier.Commands;
+import io.papermc.paper.command.brigadier.argument.SignedMessageResolver;
+import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
+import io.papermc.paper.command.brigadier.argument.resolvers.BlockPositionResolver;
+import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver;
+import io.papermc.paper.math.BlockPosition;
+import io.papermc.testplugin.TestPlugin;
+import net.kyori.adventure.chat.ChatType;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class ExampleAdminCommand {
+
+ public static void register(JavaPlugin plugin, Commands commands) {
+ final LiteralArgumentBuilder<CommandSourceStack> adminBuilder = Commands.literal("admin")
+ .executes((ct) -> {
+ ct.getSource().getSender().sendPlainMessage("root admin");
+ return 1;
+ })
+ .then(
+ Commands.literal("tp")
+ .then(
+ Commands.argument("player", ArgumentTypes.player()).executes((source) -> {
+ CommandSourceStack sourceStack = source.getSource();
+ Player resolved = source.getArgument("player", PlayerSelectorArgumentResolver.class).resolve(sourceStack).get(0);
+
+ if (resolved == source.getSource().getExecutor()) {
+ source.getSource().getExecutor().sendMessage(Component.text("Can't teleport to self!"));
+ return 0;
+ }
+ Entity entity = source.getSource().getExecutor();
+ if (entity != null) {
+ entity.teleport(resolved);
+ }
+
+ return 1;
+ })
+ )
+ )
+ .then(
+ Commands.literal("tp-self")
+ .executes((cmd) -> {
+ if (cmd.getSource().getSender() instanceof Player player) {
+ player.teleport(cmd.getSource().getLocation());
+ }
+
+ return com.mojang.brigadier.Command.SINGLE_SUCCESS;
+ })
+ )
+ .then(
+ Commands.literal("broadcast")
+ .then(
+ Commands.argument("message", ArgumentTypes.component()).executes((source) -> {
+ Component message = source.getArgument("message", Component.class);
+ Bukkit.broadcast(message);
+ return 1;
+ })
+ )
+ )
+ .then(
+ Commands.literal("ice_cream").then(
+ Commands.argument("type", new IceCreamTypeArgument()).executes((context) -> {
+ IceCreamType argumentResponse = context.getArgument("type", IceCreamType.class); // Gets the raw argument
+ context.getSource().getSender().sendMessage(Component.text("You like: " + argumentResponse));
+ return 1;
+ })
+ )
+ )
+ .then(
+ Commands.literal("execute")
+ .redirect(commands.getDispatcher().getRoot().getChild("execute"))
+ )
+ .then(
+ Commands.literal("signed_message").then(
+ Commands.argument("msg", ArgumentTypes.signedMessage()).executes((context) -> {
+ SignedMessageResolver argumentResponse = context.getArgument("msg", SignedMessageResolver.class); // Gets the raw argument
+
+ // This is a better way of getting signed messages, includes the concept of "disguised" messages.
+ argumentResponse.resolveSignedMessage("msg", context)
+ .thenAccept((signedMsg) -> {
+ context.getSource().getSender().sendMessage(signedMsg, ChatType.SAY_COMMAND.bind(Component.text("STATIC")));
+ });
+
+ return 1;
+ })
+ )
+ )
+ .then(
+ Commands.literal("setblock").then(
+ Commands.argument("block", ArgumentTypes.blockState())
+ .then(Commands.argument("pos", ArgumentTypes.blockPosition())
+ .executes((context) -> {
+ CommandSourceStack sourceStack = context.getSource();
+ BlockPosition position = context.getArgument("pos", BlockPositionResolver.class).resolve(sourceStack);
+ BlockState state = context.getArgument("block", BlockState.class);
+
+ // TODO: better block state api here? :thinking:
+ Block block = context.getSource().getLocation().getWorld().getBlockAt(position.blockX(), position.blockY(), position.blockZ());
+ block.setType(state.getType());
+ block.setBlockData(state.getBlockData());
+
+ return 1;
+ })
+ )
+ )
+ );
+ commands.register(plugin.getPluginMeta(), adminBuilder.build(), "Cool command showcasing what you can do!", List.of("alias_for_admin_that_you_shouldnt_use", "a"));
+
+
+ Bukkit.getCommandMap().register(
+ "legacy",
+ new Command("legacy_command") {
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
+ return List.of(String.join(" ", args));
+ }
+ }
+ );
+
+ Bukkit.getCommandMap().register(
+ "legacy",
+ new Command("legacy_fail") {
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ return false;
+ }
+
+ @Override
+ public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
+ return List.of(String.join(" ", args));
+ }
+ }
+ );
+ }
+}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamType.java b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamType.java
new file mode 100644
index 0000000000..cf63058fb9
--- /dev/null
+++ b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamType.java
@@ -0,0 +1,9 @@
+package io.papermc.testplugin.brigtests.example;
+
+public enum IceCreamType {
+ VANILLA,
+ CHOCOLATE,
+ BLUE_MOON,
+ STRAWBERRY,
+ WHOLE_MILK
+}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamTypeArgument.java b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamTypeArgument.java
new file mode 100644
index 0000000000..68df9e65a3
--- /dev/null
+++ b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/IceCreamTypeArgument.java
@@ -0,0 +1,47 @@
+package io.papermc.testplugin.brigtests.example;
+
+import com.mojang.brigadier.Message;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import io.papermc.paper.command.brigadier.MessageComponentSerializer;
+import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.CompletableFuture;
+
+public class IceCreamTypeArgument implements CustomArgumentType.Converted<IceCreamType, String> {
+
+ @Override
+ public @NotNull IceCreamType convert(String nativeType) throws CommandSyntaxException {
+ try {
+ return IceCreamType.valueOf(nativeType.toUpperCase());
+ } catch (Exception e) {
+ Message message = MessageComponentSerializer.message().serialize(Component.text("Invalid species %s!".formatted(nativeType), NamedTextColor.RED));
+
+ throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message);
+ }
+ }
+
+ @Override
+ public @NotNull ArgumentType<String> getNativeType() {
+ return StringArgumentType.word();
+ }
+
+ @Override
+ public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
+ for (IceCreamType species : IceCreamType.values()) {
+ builder.suggest(species.name(), MessageComponentSerializer.message().serialize(Component.text("COOL! TOOLTIP!", NamedTextColor.GREEN)));
+ }
+
+ return CompletableFuture.completedFuture(
+ builder.build()
+ );
+ }
+}
diff --git a/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/MaterialArgumentType.java b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/MaterialArgumentType.java
new file mode 100644
index 0000000000..381be0e65b
--- /dev/null
+++ b/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example/MaterialArgumentType.java
@@ -0,0 +1,88 @@
+package io.papermc.testplugin.brigtests.example;
+
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
+import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.bukkit.Keyed;
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Registry;
+import org.jetbrains.annotations.NotNull;
+
+import static net.kyori.adventure.text.Component.translatable;
+
+public class MaterialArgumentType implements CustomArgumentType.Converted<Material, NamespacedKey> {
+
+ private static final ComponentCommandExceptionType ERROR_INVALID = new ComponentCommandExceptionType(translatable("argument.id.invalid"));
+
+ private final Predicate<Material> check;
+
+ private MaterialArgumentType(Predicate<Material> check) {
+ this.check = check;
+ }
+
+ public static MaterialArgumentType item() {
+ return new MaterialArgumentType(Material::isItem);
+ }
+
+ public static MaterialArgumentType block() {
+ return new MaterialArgumentType(Material::isBlock);
+ }
+
+ @Override
+ public @NotNull Material convert(final @NotNull NamespacedKey nativeType) throws CommandSyntaxException {
+ final Material material = Registry.MATERIAL.get(nativeType);
+ if (material == null) {
+ throw ERROR_INVALID.create();
+ }
+ if (!this.check.test(material)) {
+ throw ERROR_INVALID.create();
+ }
+ return material;
+ }
+
+ static boolean matchesSubStr(String remaining, String candidate) {
+ for(int i = 0; !candidate.startsWith(remaining, i); ++i) {
+ i = candidate.indexOf('_', i);
+ if (i < 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public @NotNull ArgumentType<NamespacedKey> getNativeType() {
+ return ArgumentTypes.namespacedKey();
+ }
+
+ @Override
+ public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(final @NotNull CommandContext<S> context, final @NotNull SuggestionsBuilder builder) {
+ final Stream<Material> stream = StreamSupport.stream(Registry.MATERIAL.spliterator(), false);
+ final String remaining = builder.getRemaining();
+ boolean containsColon = remaining.indexOf(':') > -1;
+ stream.filter(this.check)
+ .map(Keyed::key)
+ .forEach(key -> {
+ final String keyAsString = key.asString();
+ if (containsColon) {
+ if (matchesSubStr(remaining, keyAsString)) {
+ builder.suggest(keyAsString);
+ }
+ } else if (matchesSubStr(remaining, key.namespace()) || "minecraft".equals(key.namespace()) && matchesSubStr(remaining, key.value())) {
+ builder.suggest(keyAsString);
+ }
+ });
+ return builder.buildFuture();
+ }
+
+}