From 2ca4ea7652603df69a3ba252500e7c29efb0d449 Mon Sep 17 00:00:00 2001 From: Aurorawr <100384210+Novampr@users.noreply.github.com> Date: Wed, 25 Jun 2025 23:21:40 +0100 Subject: [PATCH] Introduce sendCommand API method (#5582) * Introduce sendCommand API method * Ensure Geyser/extension commands are caught * Remove handleCommand from the translator, use executeCommand directly * Relocate the command handling logic again, using the new one this time * Fix up the javadocs * Rename back to sendCommand, rename the packet method * Also change the bedrock command translator * And another one... * Ensure we forward commands directly when catching exceptions during command execution --------- Co-authored-by: onebeastchris --- .../api/connection/GeyserConnection.java | 7 ++++ .../geyser/command/CommandRegistry.java | 2 +- .../geyser/command/ExceptionHandlers.java | 4 +-- .../geysermc/geyser/level/WorldManager.java | 6 ++-- .../geyser/session/GeyserSession.java | 32 ++++++++++++++++++- .../BedrockCommandRequestTranslator.java | 26 +-------------- .../bedrock/BedrockTextTranslator.java | 2 +- 7 files changed, 46 insertions(+), 33 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index aee0e5c17..0d58a71e7 100644 --- a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -107,6 +107,13 @@ public interface GeyserConnection extends Connection, CommandSource { */ void openQuickActions(); + /** + * Sends a command as if the player had executed it. + * + * @param command the command without the leading forward-slash + */ + void sendCommand(String command); + /** * @param javaId the Java entity ID to look up. * @return a {@link GeyserEntity} if present in this connection's entity tracker. diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java index 54fa70a5b..75ea81ff9 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -287,7 +287,7 @@ public class CommandRegistry implements EventRegistrar { help.execute(source); } else if (STANDALONE_COMMAND_MANAGER && source instanceof GeyserSession session) { // If we are on an appropriate platform, forward the command to the backend - session.sendCommand(context.rawInput().input()); + session.sendCommandPacket(context.rawInput().input()); } else { source.sendLocaleString(ExceptionHandlers.PERMISSION_FAIL_LANG_KEY); } diff --git a/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java b/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java index 6348b8515..444057709 100644 --- a/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java +++ b/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java @@ -89,7 +89,7 @@ final class ExceptionHandlers { (ctx, e) -> { // Let backend server receive & handle the command if (CommandRegistry.STANDALONE_COMMAND_MANAGER && ctx.sender() instanceof GeyserSession session) { - session.sendCommand(ctx.rawInput().input()); + session.sendCommandPacket(ctx.rawInput().input()); } else { ctx.sender().sendLocaleString("geyser.command.not_found"); } @@ -114,7 +114,7 @@ final class ExceptionHandlers { // Let backend server receive & handle the command if (CommandRegistry.STANDALONE_COMMAND_MANAGER && source instanceof GeyserSession session) { - session.sendCommand(context.rawInput().input()); + session.sendCommandPacket(context.rawInput().input()); return; } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 67590373c..48f9734b2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -126,7 +126,7 @@ public abstract class WorldManager { * @param value The new value for the gamerule */ public void setGameRule(GeyserSession session, String name, Object value) { - session.sendCommand("gamerule " + name + " " + value); + session.sendCommandPacket("gamerule " + name + " " + value); } /** @@ -162,7 +162,7 @@ public abstract class WorldManager { * @param gameMode the new default game mode */ public void setDefaultGameMode(GeyserSession session, GameMode gameMode) { - session.sendCommand("defaultgamemode " + gameMode.name().toLowerCase(Locale.ROOT)); + session.sendCommandPacket("defaultgamemode " + gameMode.name().toLowerCase(Locale.ROOT)); } /** @@ -172,7 +172,7 @@ public abstract class WorldManager { * @param difficulty The difficulty to change to */ public void setDifficulty(GeyserSession session, Difficulty difficulty) { - session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); + session.sendCommandPacket("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); } /** diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 06f48a966..6f9864151 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -120,6 +120,7 @@ import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.api.event.bedrock.SessionDisconnectEvent; import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent; import org.geysermc.geyser.api.network.RemoteServer; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -1510,10 +1511,39 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Sends a command to the Java server. */ - public void sendCommand(String command) { + public void sendCommandPacket(String command) { sendDownstreamGamePacket(new ServerboundChatCommandSignedPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet(), (byte) 0)); } + /** + * Runs the command through platform specific command registries if applicable + * else, it sends the command to the server. + */ + @Override + public void sendCommand(String command) { + if (MessageTranslator.isTooLong(command, this)) { + return; + } + + if (CommandRegistry.STANDALONE_COMMAND_MANAGER) { + // try to handle the command within the standalone/viaproxy command manager + String[] args = command.split(" "); + if (args.length > 0) { + String root = args[0]; + + CommandRegistry registry = GeyserImpl.getInstance().commandRegistry(); + if (registry.rootCommands().contains(root)) { + registry.runCommand(this, command); + // don't pass the command to the java server here + // will pass it through later if the user lacks permission + return; + } + } + } + + this.sendCommandPacket(command); + } + @Override public void openPauseScreenAdditions() { List additions = tagCache.get(DialogTag.PAUSE_SCREEN_ADDITIONS); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java index 27d18183d..7cd5cd98b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java @@ -39,30 +39,6 @@ public class BedrockCommandRequestTranslator extends PacketTranslator 0) { - String root = args[0]; - - CommandRegistry registry = GeyserImpl.getInstance().commandRegistry(); - if (registry.rootCommands().contains(root)) { - registry.runCommand(session, command); - // don't pass the command to the java server here - // will pass it through later if the user lacks permission - return; - } - } - } - - session.sendCommand(command); + session.sendCommand(MessageTranslator.normalizeSpace(command).substring(1)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java index bac9b9ecc..14b76b761 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java @@ -48,7 +48,7 @@ public class BedrockTextTranslator extends PacketTranslator { if (message.startsWith("/")) { // Yes, Java actually allows whitespaces before commands and will still see those as valid - BedrockCommandRequestTranslator.handleCommand(session, message.substring(1)); + session.sendCommand(message.substring(1)); return; }