1.#.#
+ */
+ private String minecraftVersion;
+
@Override
public void onEnable() {
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
@@ -118,6 +123,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
geyserConfig.loadFloodgate(this);
+ // Turn "(MC: 1.16.4)" into 1.16.4.
+ this.minecraftVersion = Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0];
+
this.connector = GeyserConnector.start(PlatformType.SPIGOT, this);
if (geyserConfig.isLegacyPingPassthrough()) {
@@ -239,6 +247,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
return new GeyserSpigotDumpInfo();
}
+ @Override
+ public String getMinecraftServerVersion() {
+ return this.minecraftVersion;
+ }
+
public boolean isCompatible(String version, String whichVersion) {
int[] currentVersion = parseVersion(version);
int[] otherVersion = parseVersion(whichVersion);
@@ -277,10 +290,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
* @return the server version before ViaVersion finishes initializing
*/
public ProtocolVersion getServerProtocolVersion() {
- String bukkitVersion = Bukkit.getServer().getVersion();
- // Turn "(MC: 1.16.4)" into 1.16.4.
- String version = bukkitVersion.split("\\(MC: ")[1].split("\\)")[0];
- return ProtocolVersion.getClosest(version);
+ return ProtocolVersion.getClosest(this.minecraftVersion);
}
/**
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java
index ae1992727..2cbec3273 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java
@@ -27,10 +27,10 @@ package org.geysermc.platform.spigot.world.manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
-import org.geysermc.adapters.spigot.SpigotAdapters;
-import org.geysermc.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
+import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
+import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java
index cb450f7f9..423156c97 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java
@@ -75,6 +75,10 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
+ if (!player.getWorld().isChunkLoaded(x >> 4, z >> 4)) {
+ // Prevent nasty async errors if a player is loading in
+ return BlockTranslator.JAVA_AIR_ID;
+ }
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
Block block = player.getWorld().getBlockAt(x, y, z);
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java
index c7e3a3d4f..469a38f17 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java
@@ -27,10 +27,10 @@ package org.geysermc.platform.spigot.world.manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
-import org.geysermc.adapters.spigot.SpigotAdapters;
-import org.geysermc.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
+import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
+import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
protected final SpigotWorldAdapter adapter;
diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java
index 5b8bf54b2..1986bbd22 100644
--- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java
+++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java
@@ -101,7 +101,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
}
}
- if (geyserConfig.getBedrock().isCloneRemotePort()){
+ if (geyserConfig.getBedrock().isCloneRemotePort()) {
geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort());
}
@@ -163,4 +163,9 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
public BootstrapDumpInfo getDumpInfo() {
return new GeyserSpongeDumpInfo();
}
+
+ @Override
+ public String getMinecraftServerVersion() {
+ return Sponge.getPlatform().getMinecraftVersion().getName();
+ }
}
diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java
index 5aa15635e..551b0e584 100644
--- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java
+++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java
@@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import lombok.Getter;
import net.minecrell.terminalconsole.TerminalConsoleAppender;
+import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
@@ -167,11 +168,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
this.onEnable();
}
- public void onEnable(boolean useGui) {
- this.useGui = useGui;
- this.onEnable();
- }
-
@Override
public void onEnable() {
Logger logger = (Logger) LogManager.getRootLogger();
@@ -213,6 +209,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
}
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
+ // Allow libraries like Protocol to have their debug information passthrough
+ logger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO);
+
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
geyserCommandManager = new GeyserCommandManager(connector);
diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java
index 9c10234f3..7eeba84bd 100644
--- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java
+++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java
@@ -55,7 +55,7 @@ public class LoopbackUtil {
if (!result.contains("minecraftuwp")) {
Files.write(Paths.get(System.getenv("temp") + "/loopback_minecraft.bat"), loopbackCommand.getBytes(), new OpenOption[0]);
- process = Runtime.getRuntime().exec(startScript);
+ Runtime.getRuntime().exec(startScript);
geyserLogger.info(ChatColor.AQUA + LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.added"));
}
diff --git a/connector/pom.xml b/connector/pom.xml
index 04fc918fa..7d08b5c60 100644
--- a/connector/pom.xml
+++ b/connector/pom.xml
@@ -10,16 +10,21 @@
null
if not applicable
+ */
+ @Nullable
+ default String getMinecraftServerVersion() {
+ return null;
+ }
}
diff --git a/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java b/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java
index 3f674d7fa..f91da11b5 100644
--- a/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java
+++ b/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java
@@ -52,7 +52,7 @@ public class IGeyserMain {
* @return The formatted message
*/
private String createMessage() {
- String message = "";
+ StringBuilder message = new StringBuilder();
InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/" + Locale.getDefault().toString() + ".txt");
@@ -68,10 +68,10 @@ public class IGeyserMain {
line = line.replace("${plugin_type}", this.getPluginType());
line = line.replace("${plugin_folder}", this.getPluginFolder());
- message += line + "\n";
+ message.append(line).append("\n");
}
- return message;
+ return message.toString();
}
/**
diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
index e21aa6bb8..6052bd283 100644
--- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
+++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
@@ -27,9 +27,11 @@ package org.geysermc.connector.configuration;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.geysermc.connector.GeyserLogger;
+import org.geysermc.connector.network.CIDRMatcher;
import org.geysermc.connector.utils.LanguageUtils;
import java.nio.file.Path;
+import java.util.List;
import java.util.Map;
public interface GeyserConfiguration {
@@ -59,6 +61,8 @@ public interface GeyserConfiguration {
int getPingPassthroughInterval();
+ boolean isForwardPlayerPing();
+
int getMaxPlayers();
boolean isDebugMode();
@@ -104,6 +108,15 @@ public interface GeyserConfiguration {
String getMotd2();
String getServerName();
+
+ boolean isEnableProxyProtocol();
+
+ Listboolean translate(Class extends P> clazz, P packet, GeyserSession session) { if (!session.getUpstream().isClosed() && !session.isClosed()) { try { - if (translators.containsKey(clazz)) { - ((PacketTranslator
) translators.get(clazz)).translate(packet, session); + PacketTranslator
translator = (PacketTranslator
) translators.get(clazz);
+ if (translator != null) {
+ translator.translate(packet, session);
return true;
} else {
- if (!IGNORED_PACKETS.contains(clazz))
+ if ((GeyserConnector.getInstance().getPlatformType() != PlatformType.STANDALONE || !(packet instanceof BedrockPacket)) && !IGNORED_PACKETS.contains(clazz)) {
+ // Other debug logs already take care of Bedrock packets for us if on standalone
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
+ }
}
} catch (Throwable ex) {
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.packet.failed", packet.getClass().getSimpleName()), ex);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java
index 64c91f076..577469fdd 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java
@@ -40,7 +40,7 @@ import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
- * Used to send the keep alive packet back to the server
+ * Used to send the forwarded keep alive packet back to the server
*/
@Translator(packet = NetworkStackLatencyPacket.class)
public class BedrockNetworkStackLatencyTranslator extends PacketTranslator
+ * Therefore, this function will return
+ * Here's an example of how the above would be presented to Bedrock (as of 1.16.200). Notice how the top two > commandArgs = new Int2ObjectOpenHashMap<>();
// Get the first node, it should be a root node
- CommandNode rootNode = packet.getNodes()[packet.getFirstNodeIndex()];
+ CommandNode rootNode = nodes[packet.getFirstNodeIndex()];
// Loop through the root nodes to get all commands
for (int nodeIndex : rootNode.getChildIndices()) {
- CommandNode node = packet.getNodes()[nodeIndex];
+ CommandNode node = nodes[nodeIndex];
// Make sure we don't have duplicated commands (happens if there is more than 1 root node)
- if (commands.containsKey(nodeIndex)) { continue; }
- if (commands.containsValue(node.getName())) { continue; }
+ if (!commandNodes.add(nodeIndex) || !knownAliases.add(node.getName().toLowerCase())) continue;
// Get and update the commandArgs list with the found arguments
if (node.getChildIndices().length >= 1) {
for (int childIndex : node.getChildIndices()) {
- commandArgs.putIfAbsent(nodeIndex, new ArrayList<>());
- commandArgs.get(nodeIndex).add(packet.getNodes()[childIndex]);
+ commandArgs.computeIfAbsent(nodeIndex, ArrayList::new).add(nodes[childIndex]);
}
}
- // Insert the command name into the list
- commands.put(nodeIndex, node.getName());
+ // Get and parse all params
+ CommandParamData[][] params = getParams(nodes[nodeIndex], nodes);
+
+ // Insert the alias name into the command list
+ commands.computeIfAbsent(params, index -> new HashSet<>()).add(node.getName().toLowerCase());
}
// The command flags, not sure what these do apart from break things
List
gamerule
command, and let's present three "subcommands" you can perform:
+ *
+ *
+ *
+ *
+ * While all three of them are indeed part of the same command, the command setting randomTickSpeed parses an int,
+ * while the others use boolean. In Bedrock, this should be presented as a separate overload to indicate that this
+ * does something a little different.
+ * gamerule doDaylightCycle true
gamerule announceAdvancements false
gamerule randomTickSpeed 3
true
if the first two are compared, as they use the same
+ * parsers. If the third is compared with either of the others, this function will return false
.
+ * CommandParamData
+ * classes of each array are identical in type, but the following class is different:
+ *
+ * overloads=[
+ * [
+ * CommandParamData(name=doDaylightCycle, optional=false, enumData=CommandEnumData(name=announceAdvancements, values=[announceAdvancements, doDaylightCycle], isSoft=false), type=STRING, postfix=null, options=[])
+ * CommandParamData(name=value, optional=false, enumData=CommandEnumData(name=value, values=[true, false], isSoft=false), type=null, postfix=null, options=[])
+ * ]
+ * [
+ * CommandParamData(name=randomTickSpeed, optional=false, enumData=CommandEnumData(name=randomTickSpeed, values=[randomTickSpeed], isSoft=false), type=STRING, postfix=null, options=[])
+ * CommandParamData(name=value, optional=false, enumData=null, type=INT, postfix=null, options=[])
+ * ]
+ * ]
+ *
+ *
+ * @return if these two can be merged into one overload.
+ */
+ private boolean isCompatible(CommandNode[] allNodes, CommandNode a, CommandNode b) {
+ if (a == b) return true;
+ if (a.getParser() != b.getParser()) return false;
+ if (a.getChildIndices().length != b.getChildIndices().length) return false;
+
+ for (int i = 0; i < a.getChildIndices().length; i++) {
+ boolean hasSimilarity = false;
+ CommandNode a1 = allNodes[a.getChildIndices()[i]];
+ // Search "b" until we find a child that matches this one
+ for (int j = 0; j < b.getChildIndices().length; j++) {
+ if (isCompatible(allNodes, a1, allNodes[b.getChildIndices()[j]])) {
+ hasSimilarity = true;
+ break;
+ }
+ }
+
+ if (!hasSimilarity) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Get the tree of every parameter node (recursive)
*
@@ -301,13 +414,10 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator