From d8bb4e97e44b17179750bd5a3927335181ba6f2f Mon Sep 17 00:00:00 2001 From: itsTyrion Date: Fri, 9 Feb 2024 22:23:16 +0100 Subject: [PATCH] Add API for custom chat completions like on Paper (#1232) * Add API for custom chat completions like on Paper, renamed enum constant to match its function, NMS and wiki-vg * add null and version checks --- .../com/velocitypowered/api/proxy/Player.java | 29 +++++++++++++++++++ .../connection/client/ConnectedPlayer.java | 26 +++++++++++++++++ .../chat/PlayerChatCompletionPacket.java | 11 +++++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index feaadfa61..7e0c59bfd 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -309,4 +309,33 @@ public interface Player extends * @return the player's client brand */ @Nullable String getClientBrand(); + + + /** + * Add custom chat completion suggestions shown to the player while typing a message. + * + * @param completions the completions to send + */ + void addCustomChatCompletions(@NotNull Collection completions); + + /** + * Remove custom chat completion suggestions shown to the player while typing a message. + * + *

Online player names can't be removed with this method, it will only affect + * custom completions added by {@link #addCustomChatCompletions(Collection)} + * or {@link #setCustomChatCompletions(Collection)}. + * + * @param completions the completions to remove + */ + void removeCustomChatCompletions(@NotNull Collection completions); + + /** + * Set the list of chat completion suggestions shown to the player while typing a message. + * + *

If completions were set previously, this method will remove them all + * and replace them with the provided completions. + * + * @param completions the completions to set + */ + void setCustomChatCompletions(@NotNull Collection completions); } \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 5963678ad..e7d70183d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -69,6 +69,7 @@ import com.velocitypowered.proxy.protocol.packet.RemoveResourcePackPacket; import com.velocitypowered.proxy.protocol.packet.chat.ChatQueue; import com.velocitypowered.proxy.protocol.packet.chat.ChatType; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; +import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket; import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderFactory; import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatPacket; import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket; @@ -961,6 +962,31 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, this.clientBrand = clientBrand; } + @Override + public void addCustomChatCompletions(@NotNull Collection completions) { + Preconditions.checkNotNull(completions, "completions"); + this.sendCustomChatCompletionPacket(completions, PlayerChatCompletionPacket.Action.ADD); + } + + @Override + public void removeCustomChatCompletions(@NotNull Collection completions) { + Preconditions.checkNotNull(completions, "completions"); + this.sendCustomChatCompletionPacket(completions, PlayerChatCompletionPacket.Action.REMOVE); + } + + @Override + public void setCustomChatCompletions(@NotNull Collection completions) { + Preconditions.checkNotNull(completions, "completions"); + this.sendCustomChatCompletionPacket(completions, PlayerChatCompletionPacket.Action.SET); + } + + private void sendCustomChatCompletionPacket(@NotNull Collection completions, + PlayerChatCompletionPacket.Action action) { + if (connection.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) { + connection.write(new PlayerChatCompletionPacket(completions.toArray(new String[0]), action)); + } + } + @Override public void spoofChatInput(String input) { Preconditions.checkArgument(input.length() <= LegacyChatPacket.MAX_SERVERBOUND_MESSAGE_LENGTH, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java index da51120ef..d07b798a5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java @@ -28,6 +28,13 @@ public class PlayerChatCompletionPacket implements MinecraftPacket { private String[] completions; private Action action; + public PlayerChatCompletionPacket() { + } + + public PlayerChatCompletionPacket(String[] completions, Action action) { + this.completions = completions; + this.action = action; + } public String[] getCompletions() { return completions; @@ -64,9 +71,9 @@ public class PlayerChatCompletionPacket implements MinecraftPacket { return handler.handle(this); } - enum Action { + public enum Action { ADD, REMOVE, - ALTER + SET } }