From 5753548b44193d2b72a4b70d3f12b7f21d6c1d1d Mon Sep 17 00:00:00 2001 From: Ross <32296125+Rossterd@users.noreply.github.com> Date: Mon, 13 Oct 2025 21:41:33 +0200 Subject: [PATCH] Fix SimpleCommand suggestion offset (#1664) * Fix command suggestion offset * fix length error * add test * checkstyle --------- Co-authored-by: Ross <2086824-trashp@users.noreply.gitlab.com> --- .../registrar/InvocableCommandRegistrar.java | 8 ++++-- .../client/ClientPlaySessionHandler.java | 2 +- .../command/SuggestionsProviderTests.java | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java b/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java index 380f45e3..847d67d1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java @@ -103,13 +103,17 @@ abstract class InvocableCommandRegistrar, .requiresWithContext((context, reader) -> requirement.test(context)) .executes(callback) .suggests((context, builder) -> { + // Offset the suggestion to the last space seperated word + int lastSpace = builder.getRemaining().lastIndexOf(' ') + 1; + final var offsetBuilder = builder.createOffset(builder.getStart() + lastSpace); + final I invocation = invocationFactory.create(context); return command.suggestAsync(invocation).thenApply(suggestions -> { for (String value : suggestions) { Preconditions.checkNotNull(value, "suggestion"); - builder.suggest(value); + offsetBuilder.suggest(value); } - return builder.build(); + return offsetBuilder.build(); }); }) .build(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index bccd8375..288315d7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -724,7 +724,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { TabCompleteResponsePacket resp = new TabCompleteResponsePacket(); resp.setTransactionId(packet.getTransactionId()); resp.setStart(startPos + 1); - resp.setLength(packet.getCommand().length() - startPos); + resp.setLength(packet.getCommand().length() - startPos - 1); resp.getOffers().addAll(offers); player.getConnection().write(resp); } diff --git a/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java b/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java index 9fe86335..fa282f71 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java @@ -18,14 +18,17 @@ package com.velocitypowered.proxy.command; import static com.mojang.brigadier.arguments.StringArgumentType.word; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import com.google.common.collect.ImmutableList; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.suggestion.Suggestions; import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.RawCommand; +import com.velocitypowered.api.command.SimpleCommand; import java.util.List; import java.util.concurrent.CompletableFuture; import org.junit.jupiter.api.Test; @@ -286,4 +289,26 @@ public class SuggestionsProviderTests extends CommandTestSuite { return ImmutableList.of(); } } + + @Test + void testSuggestionOffset() { + final var meta = manager.metaBuilder("offset").build(); + manager.register(meta, new SimpleCommand() { + @Override + public void execute(final Invocation invocation) { + fail(); + } + + @Override + public List suggest(final Invocation invocation) { + return List.of("bump"); + } + }); + + assertSuggestions("offset bu", "bump"); + for (int i = 10; i < 20; i++) { + final Suggestions suggestions = manager.offerBrigadierSuggestions(source, "offset " + "bump ".repeat(i)).join(); + assertEquals(7 + 5 * i, suggestions.getList().get(0).getRange().getStart()); + } + } }