From b0ccf45cd47f797eca2f62e5716170bc80074b86 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sat, 23 Dec 2023 18:06:06 -0800 Subject: [PATCH 01/13] Closes GeyserMC/Geyser#4358 (#4360) Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../geyser/level/block/BlockStateValues.java | 15 +++++++++++++++ .../java/org/geysermc/geyser/util/ChunkUtils.java | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 11702e78a..e665a22ef 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -67,6 +67,7 @@ public final class BlockStateValues { private static final Int2IntMap SKULL_WALL_DIRECTIONS = new Int2IntOpenHashMap(); private static final Int2ByteMap SHULKERBOX_DIRECTIONS = new FixedInt2ByteMap(); private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); + private static final IntSet UPPER_DOORS = new IntOpenHashSet(); public static final int JAVA_AIR_ID = 0; @@ -219,6 +220,10 @@ public final class BlockStateValues { if (javaId.contains("_cauldron") && !javaId.contains("water_")) { NON_WATER_CAULDRONS.add(javaBlockState); } + + if (javaId.contains("_door[") && javaId.contains("half=upper")) { + UPPER_DOORS.add(javaBlockState); + } } /** @@ -498,6 +503,16 @@ public final class BlockStateValues { return WATER_LEVEL.getOrDefault(state, -1); } + /** + * Check if a block is the upper half of a door. + * + * @param state BlockState of the block + * @return True if the block is the upper half of a door + */ + public static boolean isUpperDoor(int state) { + return UPPER_DOORS.contains(state); + } + /** * Get the height of water from the block state * This is used in FishingHookEntity to create splash sounds when the hook hits the water. In addition, diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 114a7b6de..cc21e2d0a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -215,6 +215,14 @@ public class ChunkUtils { break; //No block will be a part of two classes } } + + if (BlockStateValues.isUpperDoor(blockState)) { + // Update the lower door block as Bedrock client doesn't like door to be closed from the top + // See https://github.com/GeyserMC/Geyser/issues/4358 + Vector3i belowDoorPosition = position.sub(0, 1, 0); + int belowDoorBlockState = session.getGeyser().getWorldManager().getBlockAt(session, belowDoorPosition.getX(), belowDoorPosition.getY(), belowDoorPosition.getZ()); + updateBlock(session, belowDoorBlockState, belowDoorPosition); + } } public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) { From 592a58a0c87bf0054610f5a7ec996e65f1c0c402 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 25 Dec 2023 20:43:13 +0100 Subject: [PATCH 02/13] Use uuid for bukkit api permission checks (#4363) * lookup players by uuid instead of name * Fix: look up Players by UUID for permissions, dont throw if a player can't be found (e.g. disconnected) * use api method --- .../spigot/world/manager/GeyserSpigotWorldManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 74f359e02..42f0d17f4 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -197,7 +197,11 @@ public class GeyserSpigotWorldManager extends WorldManager { @Override public boolean hasPermission(GeyserSession session, String permission) { - return Objects.requireNonNull(Bukkit.getPlayer(session.getPlayerEntity().getUsername())).hasPermission(permission); + Player player = Bukkit.getPlayer(session.javaUuid()); + if (player != null) { + return player.hasPermission(permission); + } + return false; } @Override From 46bde0c01955cddc5b0da547f76629583f568ca4 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 31 Dec 2023 02:24:44 +0100 Subject: [PATCH 03/13] Fix: protocol being null during online mode login (#4369) * fix: protocol being null during online mode login * gimme more space * add debug logging for too early downstream packet sending --- .../java/org/geysermc/geyser/session/GeyserSession.java | 9 +++++++++ 1 file changed, 9 insertions(+) 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 28ad5887c..26e206458 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1633,6 +1633,15 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * @param intendedState the state the client should be in */ public void sendDownstreamPacket(Packet packet, ProtocolState intendedState) { + // protocol can be null when we're not yet logged in (online auth) + if (protocol == null) { + if (geyser.getConfig().isDebugMode()) { + geyser.getLogger().debug("Tried to send downstream packet with no downstream session!"); + Thread.dumpStack(); + } + return; + } + if (protocol.getState() != intendedState) { geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " state"); return; From 7613bdbafe402f86ec8f1bd7a446b2a1d6b86305 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:49:01 -0500 Subject: [PATCH 04/13] Fix https://github.com/GeyserMC/Geyser/issues/4378 --- .../org/geysermc/geyser/network/UpstreamPacketHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index a0b104adb..7a22b8a42 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -28,6 +28,8 @@ package org.geysermc.geyser.network; import io.netty.buffer.Unpooled; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; +import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat; +import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; @@ -108,6 +110,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.disconnect(disconnectMessage); return false; } else if (protocolVersion < GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { + if (protocolVersion < Bedrock_v622.CODEC.getProtocolVersion()) { + // https://github.com/GeyserMC/Geyser/issues/4378 + session.getUpstream().getSession().setCodec(BedrockCompat.CODEC_LEGACY); + } session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); return false; } else { From 3288f422b19d1eb65cbca8b36f8eb6aa4db8f582 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 12 Jan 2024 15:39:53 +0100 Subject: [PATCH 05/13] Update ViaVersion api usage (#4386) - Switch to fluent accessor, since the getter was removed after being deprecated for 3 years --- .../geysermc/geyser/platform/spigot/GeyserSpigotInjector.java | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 01bc0bea4..ad31131bd 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -150,7 +150,7 @@ public class GeyserSpigotInjector extends GeyserInjector { childHandler = (ChannelInitializer) childHandlerField.get(handler); // ViaVersion non-Paper-injector workaround so we aren't double-injecting if (isViaVersion && childHandler instanceof BukkitChannelInitializer) { - childHandler = ((BukkitChannelInitializer) childHandler).getOriginal(); + childHandler = ((BukkitChannelInitializer) childHandler).original(); } break; } catch (Exception e) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c71aa715f..9e6eeca1d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ log4j = "2.20.0" jline = "3.21.0" terminalconsoleappender = "1.2.0" folia = "1.19.4-R0.1-SNAPSHOT" -viaversion = "4.0.0" +viaversion = "4.9.2" adapters = "1.11-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" From 710dbfc1c87253779becc1551601be651612494e Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 17 Jan 2024 18:38:48 +0100 Subject: [PATCH 06/13] Bump mcpl to re-allow invalid block entity types (#4398) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9e6eeca1d..72e34e2c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ protocol-connection = "3.0.0.Beta1-20231206.150507-113" raknet = "1.0.0.CR1-20231206.145325-12" blockstateupdater="1.20.50-20231106.161340-1" mcauthlib = "d9d773e" -mcprotocollib = "1.20.4-2-20231219.074138-2" +mcprotocollib = "1.20.4-2-20240116.220521-7" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 509e00c138a52d616b8fe11917a2ff42cca2e08b Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 19 Jan 2024 00:19:07 +0100 Subject: [PATCH 07/13] Fix: Geyser on Velocity after they renamed packet class names :/ (#4399) --- .../velocity/GeyserVelocityCompressionDisabler.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityCompressionDisabler.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityCompressionDisabler.java index e787e7355..99c759767 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityCompressionDisabler.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityCompressionDisabler.java @@ -47,8 +47,14 @@ public class GeyserVelocityCompressionDisabler extends ChannelDuplexHandler { Method setCompressionMethod = null; try { - compressionPacketClass = Class.forName("com.velocitypowered.proxy.protocol.packet.SetCompression"); - loginSuccessPacketClass = Class.forName("com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess"); + try { + compressionPacketClass = Class.forName("com.velocitypowered.proxy.protocol.packet.SetCompressionPacket"); + loginSuccessPacketClass = Class.forName("com.velocitypowered.proxy.protocol.packet.ServerLoginSuccessPacket"); + } catch (Exception ignored) { + // Velocity renamed packet classes in https://github.com/PaperMC/Velocity/commit/2ac8751337befd04f4663575f5d752c748384110 + compressionPacketClass = Class.forName("com.velocitypowered.proxy.protocol.packet.SetCompression"); + loginSuccessPacketClass = Class.forName("com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess"); + } compressionEnabledEvent = Class.forName("com.velocitypowered.proxy.protocol.VelocityConnectionEvent") .getDeclaredField("COMPRESSION_ENABLED").get(null); setCompressionMethod = Class.forName("com.velocitypowered.proxy.connection.MinecraftConnection") From 16f9f0d94f98b52676f992cfbcb8db48a7808aa1 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 20 Jan 2024 12:03:32 +0100 Subject: [PATCH 08/13] Don't try to show the server settings form to players who are not logged in (#4387) * Don't show the server settings form to players who are not yet logged in * Add brackets to if statement --- .../bedrock/BedrockServerSettingsRequestTranslator.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java index fb02d7e3e..aa7a2e40f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java @@ -42,6 +42,11 @@ public class BedrockServerSettingsRequestTranslator extends PacketTranslator Date: Mon, 22 Jan 2024 19:21:12 +0100 Subject: [PATCH 09/13] Gracefully handle invalid stone cutter recipes (#4406) * Gracefully handle invalid stone cutter recipes Further various little fixes: - bump source version in AP to 17 to silence build log spam - remove unneeded close() on auto-closable resource --- .../geysermc/geyser/processor/BlockEntityProcessor.java | 2 +- .../geyser/processor/CollisionRemapperProcessor.java | 2 +- .../geyser/processor/PacketTranslatorProcessor.java | 2 +- .../geysermc/geyser/processor/SoundHandlerProcessor.java | 2 +- .../java/org/geysermc/geyser/text/MinecraftLocale.java | 1 - .../protocol/java/JavaUpdateRecipesTranslator.java | 7 +++++++ 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ap/src/main/java/org/geysermc/geyser/processor/BlockEntityProcessor.java b/ap/src/main/java/org/geysermc/geyser/processor/BlockEntityProcessor.java index f9ba68302..ccdaeda4e 100644 --- a/ap/src/main/java/org/geysermc/geyser/processor/BlockEntityProcessor.java +++ b/ap/src/main/java/org/geysermc/geyser/processor/BlockEntityProcessor.java @@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_16) +@SupportedSourceVersion(SourceVersion.RELEASE_17) public class BlockEntityProcessor extends ClassProcessor { public BlockEntityProcessor() { super("org.geysermc.geyser.translator.level.block.entity.BlockEntity"); diff --git a/ap/src/main/java/org/geysermc/geyser/processor/CollisionRemapperProcessor.java b/ap/src/main/java/org/geysermc/geyser/processor/CollisionRemapperProcessor.java index 84e2e2ffd..30d94b7f5 100644 --- a/ap/src/main/java/org/geysermc/geyser/processor/CollisionRemapperProcessor.java +++ b/ap/src/main/java/org/geysermc/geyser/processor/CollisionRemapperProcessor.java @@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_16) +@SupportedSourceVersion(SourceVersion.RELEASE_17) public class CollisionRemapperProcessor extends ClassProcessor { public CollisionRemapperProcessor() { super("org.geysermc.geyser.translator.collision.CollisionRemapper"); diff --git a/ap/src/main/java/org/geysermc/geyser/processor/PacketTranslatorProcessor.java b/ap/src/main/java/org/geysermc/geyser/processor/PacketTranslatorProcessor.java index 9b99d679b..d538a9ca1 100644 --- a/ap/src/main/java/org/geysermc/geyser/processor/PacketTranslatorProcessor.java +++ b/ap/src/main/java/org/geysermc/geyser/processor/PacketTranslatorProcessor.java @@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_16) +@SupportedSourceVersion(SourceVersion.RELEASE_17) public class PacketTranslatorProcessor extends ClassProcessor { public PacketTranslatorProcessor() { super("org.geysermc.geyser.translator.protocol.Translator"); diff --git a/ap/src/main/java/org/geysermc/geyser/processor/SoundHandlerProcessor.java b/ap/src/main/java/org/geysermc/geyser/processor/SoundHandlerProcessor.java index c35c0ee4e..30ceef2c6 100644 --- a/ap/src/main/java/org/geysermc/geyser/processor/SoundHandlerProcessor.java +++ b/ap/src/main/java/org/geysermc/geyser/processor/SoundHandlerProcessor.java @@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_16) +@SupportedSourceVersion(SourceVersion.RELEASE_17) public class SoundHandlerProcessor extends ClassProcessor { public SoundHandlerProcessor() { super("org.geysermc.geyser.translator.sound.SoundTranslator"); diff --git a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java index f6e37787d..692a05110 100644 --- a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java @@ -196,7 +196,6 @@ public class MinecraftLocale { Map.Entry entry = localeIterator.next(); langMap.put(entry.getKey(), entry.getValue().asText()); } - localeStream.close(); return langMap; } catch (FileNotFoundException e){ throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage())); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 344e06c96..7beb37af9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -169,6 +169,13 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData(); + if (stoneCuttingData.getIngredient().getOptions().length == 0) { + if (GeyserImpl.getInstance().getConfig().isDebugMode()) { + GeyserImpl.getInstance().getLogger().debug("Received broken stone cutter recipe: " + stoneCuttingData + " " + + recipe.getIdentifier() + " " + Registries.JAVA_ITEMS.get().get(stoneCuttingData.getResult().getId()).javaIdentifier()); + } + continue; + } ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0]; List data = unsortedStonecutterData.get(ingredient.getId()); if (data == null) { From 7bcecdf40376044f2dc021683716e81d31e1217c Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 23 Jan 2024 00:34:53 +0100 Subject: [PATCH 10/13] Fix: Opening inventory menus in spectator mode (#4407) Revert to spectator_viewer instead of the native Bedrock spectator menu. While it looks uglier - e.g. it's showing health/hunger bars; it allows opening menus. It'll also be needed for entity spectating, since clicking on things isnt possible in bedrocks spectator mode --- core/src/main/java/org/geysermc/geyser/util/EntityUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java index 68753c009..583e15c23 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -270,7 +270,7 @@ public final class EntityUtils { return switch (gamemode) { case CREATIVE -> GameType.CREATIVE; case ADVENTURE -> GameType.ADVENTURE; - case SPECTATOR -> GameType.SPECTATOR; + case SPECTATOR -> GameType.SURVIVAL_VIEWER; default -> GameType.SURVIVAL; }; } From 97ba6a25e6c34a4825e50bdd76636fbfad2a9c86 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 24 Jan 2024 21:18:09 +0100 Subject: [PATCH 11/13] Don't warn if clients send subchunkrequest packets (#4395) --- .../org/geysermc/geyser/network/LoggingPacketHandler.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 5076dbeb2..cf794261b 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -285,6 +285,11 @@ public class LoggingPacketHandler implements BedrockPacketHandler { return defaultHandler(packet); } + @Override + public PacketSignal handle(SubChunkRequestPacket packet) { + return defaultHandler(packet); + } + @Override public PacketSignal handle(SubClientLoginPacket packet) { return defaultHandler(packet); From 3f577f41281618b23e022ba8ed727ce9d41c3d8e Mon Sep 17 00:00:00 2001 From: rtm516 Date: Wed, 24 Jan 2024 21:20:30 +0000 Subject: [PATCH 12/13] Add fetching MC versions and Console from the extensions API (#4168) * Add fetching MC versions and Console from the extensions API * Address reviews, expose custom MinecraftVersion interface * Rename of McVersion -> MinecraftVersionImpl; proper nonnull annotation * fluent consoleCommandSource(), change MinecraftVersion#name() to versionString() * Javadocs adjustments * Create impl package and move `MinecraftVersionImpl` there * api version bump --------- Co-authored-by: onebeastchris --- .../org/geysermc/geyser/api/GeyserApi.java | 26 ++++++++++ .../geyser/api/util/MinecraftVersion.java | 49 +++++++++++++++++++ .../java/org/geysermc/geyser/GeyserImpl.java | 30 ++++++++++-- .../geyser/impl/MinecraftVersionImpl.java | 31 ++++++++++++ gradle.properties | 2 +- 5 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/util/MinecraftVersion.java create mode 100644 core/src/main/java/org/geysermc/geyser/impl/MinecraftVersionImpl.java diff --git a/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java index 0d6007c1c..a9327d0db 100644 --- a/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -29,12 +29,14 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; import org.geysermc.api.GeyserApiBase; +import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.extension.ExtensionManager; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; +import org.geysermc.geyser.api.util.MinecraftVersion; import org.geysermc.geyser.api.util.PlatformType; import java.nio.file.Path; @@ -134,6 +136,30 @@ public interface GeyserApi extends GeyserApiBase { @NonNull PlatformType platformType(); + /** + * Gets the version of Java Minecraft that is supported. + * + * @return the supported version of Java Minecraft + */ + @NonNull + MinecraftVersion supportedJavaVersion(); + + /** + * Gets a list of Bedrock Minecraft versions that are supported. + * + * @return the list of supported Bedrock Minecraft versions + */ + @NonNull + List supportedBedrockVersions(); + + /** + * Gets the {@link CommandSource} for the console. + * + * @return the console command source + */ + @NonNull + CommandSource consoleCommandSource(); + /** * Gets the current {@link GeyserApiBase} instance. * diff --git a/api/src/main/java/org/geysermc/geyser/api/util/MinecraftVersion.java b/api/src/main/java/org/geysermc/geyser/api/util/MinecraftVersion.java new file mode 100644 index 000000000..34a4b59af --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/util/MinecraftVersion.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.util; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Represents a Minecraft version. + */ +public interface MinecraftVersion { + + /** + * Gets the Minecraft version as a String. + * Example: "1.20.2", or "1.20.40/1.20.41" + * + * @return the version string + */ + @NonNull String versionString(); + + /** + * Gets the protocol version of this Minecraft version. + * + * @return the protocol version + */ + int protocolVersion(); +} diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index aef2288d6..13212b161 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -42,7 +42,11 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.geysermc.api.Geyser; +import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.api.util.MinecraftVersion; +import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.erosion.packet.Packets; @@ -60,14 +64,15 @@ import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.erosion.UnixSocketClientListener; import org.geysermc.geyser.event.GeyserEventBus; import org.geysermc.geyser.extension.GeyserExtensionManager; +import org.geysermc.geyser.impl.MinecraftVersionImpl; import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.GeyserServer; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -111,8 +116,8 @@ public class GeyserImpl implements GeyserApi { .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); public static final String NAME = "Geyser"; - public static final String GIT_VERSION = "${gitVersion}"; // A fallback for running in IDEs - public static final String VERSION = "${version}"; // A fallback for running in IDEs + public static final String GIT_VERSION = "${gitVersion}"; + public static final String VERSION = "${version}"; public static final String BUILD_NUMBER = "${buildNumber}"; public static final String BRANCH = "${branch}"; @@ -683,6 +688,25 @@ public class GeyserImpl implements GeyserApi { return platformType; } + @Override + public @NonNull MinecraftVersion supportedJavaVersion() { + return new MinecraftVersionImpl(GameProtocol.getJavaMinecraftVersion(), GameProtocol.getJavaProtocolVersion()); + } + + @Override + public @NonNull List supportedBedrockVersions() { + ArrayList versions = new ArrayList<>(); + for (BedrockCodec codec : GameProtocol.SUPPORTED_BEDROCK_CODECS) { + versions.add(new MinecraftVersionImpl(codec.getMinecraftVersion(), codec.getProtocolVersion())); + } + return Collections.unmodifiableList(versions); + } + + @Override + public @NonNull CommandSource consoleCommandSource() { + return getLogger(); + } + public int buildNumber() { if (!this.isProductionEnvironment()) { return 0; diff --git a/core/src/main/java/org/geysermc/geyser/impl/MinecraftVersionImpl.java b/core/src/main/java/org/geysermc/geyser/impl/MinecraftVersionImpl.java new file mode 100644 index 000000000..121d33c64 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/impl/MinecraftVersionImpl.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.impl; + +import org.geysermc.geyser.api.util.MinecraftVersion; + +public record MinecraftVersionImpl(String versionString, int protocolVersion) implements MinecraftVersion { +} diff --git a/gradle.properties b/gradle.properties index b6425f76d..93db310ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.2.0-SNAPSHOT +version=2.2.1-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. \ No newline at end of file From 61b3ffd0deaa1d5183965aee774b8f14be1c6424 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 24 Jan 2024 22:28:03 +0100 Subject: [PATCH 13/13] Feature: Allow setting a different port in the motd (#4293) * Allow changing the broadcasted port using a system property. This may be needed if the port Geyser runs on & the port Bedrock players connect on do not match - e.g. due to port forwarding/different routing. * initial stab at making the broadcast port an (unsafe) config option * Automatically set broadcast port to be the bind port unless manually overridden * Warn about broadcast port mismatch * Use 0 instead of -1 as indicator to broadcast the port geyser is running on --- .../geyser/api/network/BedrockListener.java | 8 ++++ .../java/org/geysermc/geyser/GeyserImpl.java | 16 +++++++ .../defaults/ConnectionTestCommand.java | 46 ++++++++++++------- .../configuration/GeyserConfiguration.java | 2 + .../GeyserJacksonConfiguration.java | 9 ++++ .../geyser/network/netty/GeyserServer.java | 16 ++++++- core/src/main/resources/config.yml | 3 ++ 7 files changed, 81 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java b/api/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java index 61fe286aa..af35d7ad1 100644 --- a/api/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java +++ b/api/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java @@ -50,6 +50,14 @@ public interface BedrockListener { */ int port(); + /** + * Gets the broadcast port that's sent to Bedrock clients with the motd. + * This is the port that Bedrock clients will connect with. It usually does not differ from the listening port. + * + * @return the broadcast port + */ + int broadcastPort(); + /** * Gets the primary MOTD shown to Bedrock players if a ping passthrough setting is not enabled. *

diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 13212b161..e9ea08260 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -314,6 +314,22 @@ public class GeyserImpl implements GeyserApi { } } + String broadcastPort = System.getProperty("geyserBroadcastPort", ""); + if (!broadcastPort.isEmpty()) { + int parsedPort; + try { + parsedPort = Integer.parseInt(broadcastPort); + if (parsedPort < 1 || parsedPort > 65535) { + throw new NumberFormatException("The broadcast port must be between 1 and 65535 inclusive!"); + } + } catch (NumberFormatException e) { + logger.error(String.format("Invalid broadcast port: %s! Defaulting to configured port.", broadcastPort + " (" + e.getMessage() + ")")); + parsedPort = config.getBedrock().port(); + } + config.getBedrock().setBroadcastPort(parsedPort); + logger.info("Broadcast port set from system property: " + parsedPort); + } + boolean floodgatePresent = bootstrap.testFloodgatePluginPresent(); if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java index ad51826c3..981c97595 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java @@ -31,6 +31,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; +import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoopbackUtil; @@ -84,7 +85,7 @@ public class ConnectionTestCommand extends GeyserCommand { return; } } else { - port = 19132; + port = geyser.getConfig().getBedrock().broadcastPort(); } String ip = fullAddress[0]; @@ -112,30 +113,41 @@ public class ConnectionTestCommand extends GeyserCommand { return; } - // Issue: do the ports not line up? - if (port != geyser.getConfig().getBedrock().port()) { - if (fullAddress.length == 2) { - sender.sendMessage("The port you are testing with (" + port + ") is not the same as you set in your Geyser configuration (" - + geyser.getConfig().getBedrock().port() + ")"); - sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `port` in the config."); - if (geyser.getConfig().getBedrock().isCloneRemotePort()) { - sender.sendMessage("You have `clone-remote-port` enabled. This option ignores the `bedrock` `port` in the config, and uses the Java server port instead."); + GeyserConfiguration config = geyser.getConfig(); + + // Issue: do the ports not line up? We only check this if players don't override the broadcast port - if they do, they (hopefully) know what they're doing + if (config.getBedrock().broadcastPort() == config.getBedrock().port()) { + if (port != config.getBedrock().port()) { + if (fullAddress.length == 2) { + sender.sendMessage("The port you are testing with (" + port + ") is not the same as you set in your Geyser configuration (" + + config.getBedrock().port() + ")"); + sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `port` in the config."); + if (config.getBedrock().isCloneRemotePort()) { + sender.sendMessage("You have `clone-remote-port` enabled. This option ignores the `bedrock` `port` in the config, and uses the Java server port instead."); + } + } else { + sender.sendMessage("You did not specify the port to check (add it with \":\"), " + + "and the default port 19132 does not match the port in your Geyser configuration (" + + config.getBedrock().port() + ")!"); + sender.sendMessage("Re-run the command with that port, or change the port in the config under `bedrock` `port`."); } - } else { - sender.sendMessage("You did not specify the port to check (add it with \":\"), " + - "and the default port 19132 does not match the port in your Geyser configuration (" - + geyser.getConfig().getBedrock().port() + ")!"); - sender.sendMessage("Re-run the command with that port, or change the port in the config under `bedrock` `port`."); + } + } else { + if (config.getBedrock().broadcastPort() != port) { + sender.sendMessage("The port you are testing with (" + port + ") is not the same as the broadcast port set in your Geyser configuration (" + + config.getBedrock().broadcastPort() + "). "); + sender.sendMessage("You ONLY need to change the broadcast port if clients connects with a port different from the port Geyser is running on."); + sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `broadcast-port` in the config."); } } // Issue: is the `bedrock` `address` in the config different? - if (!geyser.getConfig().getBedrock().address().equals("0.0.0.0")) { + if (!config.getBedrock().address().equals("0.0.0.0")) { sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional."); } // Issue: did someone turn on enable-proxy-protocol, and they didn't mean it? - if (geyser.getConfig().getBedrock().isEnableProxyProtocol()) { + if (config.getBedrock().isEnableProxyProtocol()) { sender.sendMessage("You have the `enable-proxy-protocol` setting enabled. " + "Unless you're deliberately using additional software that REQUIRES this setting, you may not need it enabled."); } @@ -166,7 +178,7 @@ public class ConnectionTestCommand extends GeyserCommand { String connectionTestMotd = "Geyser Connection Test " + randomStr; CONNECTION_TEST_MOTD = connectionTestMotd; - sender.sendMessage("Testing server connection now. Please wait..."); + sender.sendMessage("Testing server connection to " + ip + " with port: " + port + " now. Please wait..."); JsonNode output; try { String hostname = URLEncoder.encode(ip, StandardCharsets.UTF_8); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index f9bb15b32..d12ab79e9 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -122,6 +122,8 @@ public interface GeyserConfiguration { void setPort(int port); + void setBroadcastPort(int broadcastPort); + boolean isCloneRemotePort(); int getCompressionLevel(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index 0874daa07..b3b7e8cd4 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -172,6 +172,15 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration return port; } + @Setter + @JsonProperty("broadcast-port") + private int broadcastPort = 0; + + @Override + public int broadcastPort() { + return broadcastPort; + } + @Getter @JsonProperty("clone-remote-port") private boolean cloneRemotePort = false; diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index 20340826f..401a7f2cf 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -102,6 +102,11 @@ public final class GeyserServer { private ChannelFuture bootstrapFuture; + /** + * The port to broadcast in the pong. This can be different from the port the server is bound to, e.g. due to port forwarding. + */ + private final int broadcastPort; + public GeyserServer(GeyserImpl geyser, int threadCount) { this.geyser = geyser; this.group = TRANSPORT.eventLoopGroupFactory().apply(threadCount); @@ -115,6 +120,13 @@ public final class GeyserServer { } else { this.proxiedAddresses = null; } + + // It's set to 0 only if no system property or manual config value was set + if (geyser.getConfig().getBedrock().broadcastPort() == 0) { + geyser.getConfig().getBedrock().setBroadcastPort(geyser.getConfig().getBedrock().port()); + } + + this.broadcastPort = geyser.getConfig().getBedrock().broadcastPort(); } public CompletableFuture bind(InetSocketAddress address) { @@ -243,8 +255,8 @@ public final class GeyserServer { .nintendoLimited(false) .protocolVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) .version(GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()) // Required to not be empty as of 1.16.210.59. Can only contain . and numbers. - .ipv4Port(this.geyser.getConfig().getBedrock().port()) - .ipv6Port(this.geyser.getConfig().getBedrock().port()) + .ipv4Port(this.broadcastPort) + .ipv6Port(this.broadcastPort) .serverId(bootstrapFuture.channel().config().getOption(RakChannelOption.RAK_GUID)); if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) { diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index b10c2788e..0617b316c 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -30,6 +30,9 @@ bedrock: # How much to compress network traffic to the Bedrock client. The higher the number, the more CPU usage used, but # the smaller the bandwidth used. Does not have any effect below -1 or above 9. Set to -1 to disable. compression-level: 6 + # The port to broadcast to Bedrock clients with the MOTD that they should use to connect to the server. + # DO NOT uncomment and change this unless Geyser runs on a different internal port than the one that is used to connect. + # broadcast-port: 19132 # Whether to enable PROXY protocol or not for clients. You DO NOT WANT this feature unless you run UDP reverse proxy # in front of your Geyser instance. enable-proxy-protocol: false