Ensure we send commands/chat the same way a Java client would

This commit is contained in:
onebeastchris 2024-05-29 21:42:07 +02:00
parent 0fcf0f9b4f
commit 0980547da2
3 changed files with 49 additions and 6 deletions

View file

@ -26,8 +26,8 @@
package org.geysermc.geyser.translator.protocol.bedrock; package org.geysermc.geyser.translator.protocol.bedrock;
import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
@ -39,15 +39,17 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
@Override @Override
public void translate(GeyserSession session, CommandRequestPacket packet) { public void translate(GeyserSession session, CommandRequestPacket packet) {
String command = MessageTranslator.convertToPlainText(packet.getCommand()); String command = MessageTranslator.convertToPlainText(packet.getCommand());
handleCommand(session, MessageTranslator.normalizeSpace(command).substring(1));
}
public static void handleCommand(GeyserSession session, String command) {
if (!(session.getGeyser().getPlatformType() == PlatformType.STANDALONE if (!(session.getGeyser().getPlatformType() == PlatformType.STANDALONE
&& GeyserImpl.getInstance().commandManager().runCommand(session, command.substring(1)))) { && GeyserImpl.getInstance().commandManager().runCommand(session, command))) {
if (MessageTranslator.isTooLong(command, session)) { if (MessageTranslator.isTooLong(command, session)) {
return; return;
} }
// running commands via Bedrock's command select menu adds a trailing whitespace which Java doesn't like session.sendCommand(command);
// https://github.com/GeyserMC/Geyser/issues/3877
session.sendCommand(command.substring(1).stripTrailing());
} }
} }
} }

View file

@ -31,12 +31,21 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import static org.geysermc.geyser.translator.text.MessageTranslator.normalizeSpace;
@Translator(packet = TextPacket.class) @Translator(packet = TextPacket.class)
public class BedrockTextTranslator extends PacketTranslator<TextPacket> { public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
@Override @Override
public void translate(GeyserSession session, TextPacket packet) { public void translate(GeyserSession session, TextPacket packet) {
String message = MessageTranslator.convertToPlainText(packet.getMessage()); // Java trims all messages, and then checks for the leading slash
String message = MessageTranslator.convertToPlainText(normalizeSpace(packet.getMessage()));
if (message.startsWith("/")) {
// Yes, Java actually allows whitespaces before commands and will still see those as valid
BedrockCommandRequestTranslator.handleCommand(session, message.substring(1));
return;
}
if (message.isBlank()) { if (message.isBlank()) {
// Java Edition (as of 1.17.1) just doesn't pass on these messages, so... we won't either! // Java Edition (as of 1.17.1) just doesn't pass on these messages, so... we won't either!

View file

@ -387,6 +387,38 @@ public class MessageTranslator {
return false; return false;
} }
/**
* Normalizes whitespaces - a thing a vanilla client apparently does with commands and chat messages.
*/
public static String normalizeSpace(String string) {
if (string == null || string.isEmpty()) {
return string;
}
final int size = string.length();
final char[] newChars = new char[size];
int count = 0;
int whitespacesCount = 0;
boolean startWhitespaces = true;
for (int i = 0; i < size; i++) {
final char actualChar = string.charAt(i);
final boolean isWhitespace = Character.isWhitespace(actualChar);
if (isWhitespace) {
if (whitespacesCount == 0 && !startWhitespaces) {
newChars[count++] = ' ';
}
whitespacesCount++;
} else {
startWhitespaces = false;
newChars[count++] = (actualChar == 160 ? 32 : actualChar);
whitespacesCount = 0;
}
}
if (startWhitespaces) {
return "";
}
return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
}
public static void init() { public static void init() {
// no-op // no-op
} }