Don't allow the sub-MOTD to be empty (#1933)

As of 1.16.210.59, the sub-MOTD cannot be blank: https://bugs.mojang.com/browse/MCPE-117979

This workaround will be implemented now so the widest range of Geyser versions will properly show a ping in 1.16.210 - better an 'outdated server' message than 'unable to connect to world.'
This commit is contained in:
Camotoy 2021-02-15 21:41:11 -05:00 committed by GitHub
parent 93a74d669d
commit 1f1d94aa81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 13 deletions

View file

@ -42,6 +42,15 @@ import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
public class ConnectorServerEventHandler implements BedrockServerEventHandler {
/*
The following constants are all used to ensure the ping does not reach a length where it is unparsable by the Bedrock client
*/
private static final int MINECRAFT_VERSION_BYTES_LENGTH = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion().getBytes(StandardCharsets.UTF_8).length;
private static final int BRAND_BYTES_LENGTH = GeyserConnector.NAME.getBytes(StandardCharsets.UTF_8).length;
/**
* The MOTD, sub-MOTD and Minecraft version ({@link #MINECRAFT_VERSION_BYTES_LENGTH}) combined cannot reach this length.
*/
private static final int MAGIC_RAKNET_LENGTH = 338;
private final GeyserConnector connector;
@ -72,13 +81,13 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
pong.setGameType("Survival"); // Can only be Survival or Creative as of 1.16.210.59
pong.setNintendoLimited(false);
pong.setProtocolVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion());
pong.setVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); // Required to not be empty as of 1.16.210.59
pong.setVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); // Required to not be empty as of 1.16.210.59. Can only contain . and numbers.
pong.setIpv4Port(config.getBedrock().getPort());
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n");
String mainMotd = motd[0]; // First line of the motd.
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
String subMotd = (motd.length != 1) ? motd[1] : GeyserConnector.NAME; // Second line of the motd if present, otherwise default.
pong.setMotd(mainMotd.trim());
pong.setSubMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit.
@ -95,22 +104,28 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
pong.setMaximumPlayerCount(config.getMaxPlayers());
}
if (pong.getMotd() == null) {
pong.setMotd("");
// Fallbacks to prevent errors and allow Bedrock to see the server
if (pong.getMotd() == null || pong.getMotd().trim().isEmpty()) {
pong.setMotd(GeyserConnector.NAME);
}
if (pong.getSubMotd() == null) {
pong.setSubMotd("");
if (pong.getSubMotd() == null || pong.getSubMotd().trim().isEmpty()) {
// Sub-MOTD cannot be empty as of 1.16.210.59
pong.setSubMotd(GeyserConnector.NAME);
}
// The ping will not appear if the MOTD + sub-MOTD is of a certain length.
// We don't know why, though
byte[] motdArray = pong.getMotd().getBytes(StandardCharsets.UTF_8);
if (motdArray.length + pong.getSubMotd().getBytes(StandardCharsets.UTF_8).length > 338) {
// Remove the sub-MOTD first since that only appears locally
pong.setSubMotd("");
if (motdArray.length > 338) {
int subMotdLength = pong.getSubMotd().getBytes(StandardCharsets.UTF_8).length;
if (motdArray.length + subMotdLength > (MAGIC_RAKNET_LENGTH - MINECRAFT_VERSION_BYTES_LENGTH)) {
// Shorten the sub-MOTD first since that only appears locally
if (subMotdLength > BRAND_BYTES_LENGTH) {
pong.setSubMotd(GeyserConnector.NAME);
subMotdLength = BRAND_BYTES_LENGTH;
}
if (motdArray.length > (MAGIC_RAKNET_LENGTH - MINECRAFT_VERSION_BYTES_LENGTH - subMotdLength)) {
// If the top MOTD is still too long, we chop it down
byte[] newMotdArray = new byte[339];
byte[] newMotdArray = new byte[MAGIC_RAKNET_LENGTH - MINECRAFT_VERSION_BYTES_LENGTH - subMotdLength];
System.arraycopy(motdArray, 0, newMotdArray, 0, newMotdArray.length);
pong.setMotd(new String(newMotdArray, StandardCharsets.UTF_8));
}

View file

@ -18,8 +18,9 @@ bedrock:
# This option is for the plugin version only.
clone-remote-port: false
# The MOTD that will be broadcasted to Minecraft: Bedrock Edition clients. This is irrelevant if "passthrough-motd" is set to true
motd1: "GeyserMC"
motd2: "Another GeyserMC forced host."
# If either of these are empty, the respective string will default to "Geyser"
motd1: "Geyser"
motd2: "Another Geyser server."
# The Server Name that will be sent to Minecraft: Bedrock Edition clients. This is visible in both the pause menu and the settings menu.
server-name: "Geyser"
remote: