Skip to content

fix(commands): repair Bedrock command completion - #427

Closed
AlexProgrammerDE wants to merge 1 commit into
ViaVersionAddons:mainfrom
AlexProgrammerDE:codex/fix-bedrock-command-completion
Closed

AlexProgrammerDE wants to merge 1 commit into
ViaVersionAddons:mainfrom
AlexProgrammerDE:codex/fix-bedrock-command-completion

Conversation

@AlexProgrammerDE

@AlexProgrammerDE AlexProgrammerDE commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

What failed

In a live Java 26.3 client, /time arrived as three sibling argument nodes: TimeModeAdd, TimeModeSet, and TimeModeQuery. Each node used minecraft:ask_server. The Java client cancels the previous server suggestion request when another sibling makes one, while Brigadier waits for all sibling results. This leaves /time s without completion. The proxy itself returned set for /time s, so the value was present before translation.

The Bedrock Available Commands packet describes command names, aliases, overloads, and enum values. We turn that data into a Java Brigadier tree. The changes below address separate errors in that translation.

Why each change is here

  • Use Java literals for fixed, single-value hard enums. Each /time overload has a fixed mode such as set. A literal lets the Java client complete s locally and distinguish the overloads without three server requests. The conversion excludes soft enums, constrained enums, and values with whitespace. Those values need an argument node because they can change, have visibility rules, or cannot form one Brigadier literal.
  • Advertise one ask_server provider per group of sibling arguments. The client packet carries one provider marker, while the proxy's Brigadier tree keeps every provider. One client request calls CommandsStorage.complete. The proxy collects suggestions from the applicable siblings and sends the combined result. This avoids cancellation for commands that still need server suggestions.
  • Index command nodes by identity. Brigadier compares nodes by structure. A regular HashMap can give two distinct nodes the same packet index when their structure matches. IdentityHashMap keeps indices tied to the actual nodes referenced by child and redirect edges. The set of nodes marked for server suggestions uses identity for the same reason. This protects tree serialization. It was not the observed cause of /time s.
  • Keep the packet's command name as the primary literal and register every alias. Bedrock sends the name and alias enum as separate fields. The old code chose an arbitrary enum value as the primary name because the values live in a hash map. It also ignored an alias enum with one value. The primary name is now stable, and a single alias works too.
  • Apply HIDDEN_FROM_PLAYER on its own. The Java tree belongs to a player. The old filter hid a command only when the player, command block, and automation flags were all set. A command hidden from players can still be available to command blocks or automation, so those flags do not decide player visibility.
  • Make a command root executable when its parameters are all optional. The existing tree marked later nodes executable before optional trailing parameters. It missed the valid zero-argument form when every parameter was optional. The all-optional check prevents a root with a required parameter from becoming executable.
  • Consume target arguments in the proxy parser. TargetArgumentType.parse previously returned without advancing the cursor. The proxy could not reach a following argument or its suggestions. It now consumes a player name or selector, including quoted spaces inside selector brackets, and stops at the next argument separator. It rejects empty tokens and unclosed quotes or selector brackets. The Bedrock server still validates the target syntax when the command runs.
  • Remove the duplicate enum expansion branch. Both paths created the same Java enum argument and suggestions. The Bedrock flag only changes how the enum appears in the Bedrock command UI, so removing that redundant branch does not remove a Java behavior.

Verification

  • ./gradlew compileJava checkstyleMain --no-daemon passed.
  • git diff --check passed.
  • A Brigadier check suggested next after @e[name="two words"] n.

The patched jar has not been loaded into the running client and proxy, so the in-game result still needs verification.

Remaining work

This PR does not complete every Bedrock command grammar. The decoder discards command-level chained subcommand indexes. The tree builder skips chained subcommand parameters and postfixes, and an enum-as-chained-command parameter still throws. These need representative packet data and a separate grammar translation. Generic ID arguments also have no Bedrock-specific value suggestions.

The Java client cancels earlier server suggestion requests when sibling arguments all ask for completion. Emit fixed singleton enum values as literals and mark only one sibling for server suggestions so the proxy can merge the results.

Keep canonical command names and aliases, consume target arguments, and preserve optional root execution and player visibility when building the Java command tree.
@AlexProgrammerDE
AlexProgrammerDE marked this pull request as draft September 25, 2026 10:05
@AlexProgrammerDE
AlexProgrammerDE marked this pull request as ready for review September 25, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant