JorelAli / CommandAPI

A Bukkit/Spigot API for the command UI introduced in Minecraft 1.13
https://commandapi.jorel.dev
MIT License
537 stars 67 forks source link

Dynamically Updated MultiLiteral Argument #513

Open CollidaCube opened 10 months ago

CollidaCube commented 10 months ago

Description

Currently, with StringArgument, you can provide a list of suggestions dynamically for the player to chose from using .replaceSuggestions(...) but it will really accept any token. There is also MultiLiteralArgument which has a hard-coded list of accepted values and considers any other token invalid. I would like to see an in-between where you can dynamically provide a list of accepted values and the argument will mark any other token as invalid.

Expected code

// Optimally, I imagine this // Variation 1:

new MultiLiteralArgument("messageId").replaceSuggestions(
        ArgumentSuggestions.stringCollection(info -> EconomyManager.getAllEconomyIds())
);

// Variation 2:

new MultiLiteralArgument("messageId", ArgumentSuggestions.stringCollection(info -> EconomyManager.getAllEconomyIds()));

// This could work too

new StringArgument("messageId")
        .replaceSuggestions(
                ArgumentSuggestions.stringCollection(info -> EconomyManager.getAllEconomyIds())
                        .withRequirement(args -> args.suggestions().contains(args.currentArg()))
        );

// Or a new argument altogether

new DynamicallyUpdatedLiteralArgument("messageId").replaceSuggestions(...);

Extra details

No response

JorelAli commented 6 months ago

This is a limitation of Brigadier.

The MultiLiteralArgument is syntactic sugar for a collection of LiteralArgument objects, which each use an underlying Brigadier LiteralCommandNode which can accept a string literal of your choice (consisting of any sequence of characters). This list of literals is sent from your Minecraft server to your client upon login, or whenever updated (e.g. player.updateCommands()). Because the list is sent to the client, the client can validate these client-side.

The StringArgument is a simple Brigadier StringTypeArgument with suggestions. These suggestions are sent from the server to the player while the player is typing the command - they're not used for validation, but they provide a "close enough" approximation to what you're trying to achieve. Suggestions can be validated server-side (e.g. in your .executes() method) if your input must conform to a specific set of values.

It's not possible to create a dynamically changing list of suggestions without restructing the command tree during the running of the server and updating the player's list of commands which is not something that we can do easily or quickly on a per-player basis.

willkroboth commented 4 months ago

An experimental implementation of this idea is present on the dev/command-build-rewrite branch https://github.com/JorelAli/CommandAPI/commit/83ee2cfcb786fd4a885c7e0932737e82c17d17f6. I'm reopening this issue for tracking.