From 3d7e62a408b2b4a6f86430e940a0219c5b595fa0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:35:03 -0400 Subject: [PATCH 1/2] Fix some server switching issues and GeyserConnect --- .../type/player/SessionPlayerEntity.java | 2 +- .../geysermc/geyser/level/JavaDimension.java | 5 ++++- .../geyser/session/GeyserSession.java | 10 ++++++++- .../geyser/session/cache/ChunkCache.java | 14 ++---------- .../protocol/java/JavaLoginTranslator.java | 22 ++++++++----------- .../JavaHorseScreenOpenTranslator.java | 6 ++++- .../JavaLevelChunkWithLightTranslator.java | 4 ++-- .../org/geysermc/geyser/util/ChunkUtils.java | 6 ++--- .../geysermc/geyser/util/DimensionUtils.java | 2 +- .../geysermc/geyser/util/InventoryUtils.java | 2 +- 10 files changed, 37 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index dc0545cee..b924461af 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -321,7 +321,7 @@ public class SessionPlayerEntity extends PlayerEntity { public int voidFloorPosition() { // The void floor is offset about 40 blocks below the bottom of the world - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension bedrockDimension = session.getBedrockDimension(); return bedrockDimension.minY() - 40; } diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 7462844fc..0ca428830 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -34,6 +34,9 @@ import org.geysermc.geyser.util.DimensionUtils; * Represents the information we store from the current Java dimension * @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension. * This controls if they have the shaking effect applied in the dimension. + * @param bedrockId the Bedrock dimension ID of this dimension. + * As a Java dimension can be null in some login cases (e.g. GeyserConnect), make sure the player + * is logged in before utilizing this field. */ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale, int bedrockId, boolean isNetherLike) { @@ -46,7 +49,7 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world // Set if piglins/hoglins should shake boolean piglinSafe = dimension.getBoolean("piglin_safe"); // Load world coordinate scale for the world border - double coordinateScale = dimension.getDouble("coordinate_scale"); + double coordinateScale = dimension.getNumber("coordinate_scale").doubleValue(); // FIXME see if we can change this in the NBT library itself. boolean isNetherLike; // Cache the Bedrock version of this dimension, and base it off the ID - THE ID CAN CHANGE!!! 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 60321ea75..9a990865e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -137,6 +137,7 @@ import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.BlockItem; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.network.netty.LocalSession; @@ -386,6 +387,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @MonotonicNonNull @Setter private JavaDimension dimensionType = null; + /** + * Which dimension Bedrock understands themselves to be in. + * This should only be set after the ChangeDimensionPacket is sent, or + * right before the StartGamePacket is sent. + */ + @Setter + private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD; @Setter private int breakingBlock; @@ -1547,7 +1555,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(-1L); - startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(chunkCache.getBedrockDimension())); + startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(bedrockDimension)); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGameType(GameType.SURVIVAL); startGamePacket.setDifficulty(1); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java index 7b279857a..ad5237c23 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java @@ -25,17 +25,14 @@ package org.geysermc.geyser.session.cache; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.level.BedrockDimension; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.chunk.GeyserChunk; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; public class ChunkCache { private final boolean cache; @@ -46,13 +43,6 @@ public class ChunkCache { @Setter private int heightY; - /** - * Which dimension Bedrock understands themselves to be in. - */ - @Getter - @Setter - private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD; - public ChunkCache(GeyserSession session) { this.cache = !session.getGeyser().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing chunks = cache ? new Long2ObjectOpenHashMap<>() : null; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index cf4b7058b..a6d6e6c70 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -64,14 +64,17 @@ public class JavaLoginTranslator extends PacketTranslator> 4) - 1; int sectionCount; @@ -509,7 +509,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator entry : session.getItemFrameCache().entrySet()) { 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 2e7df51bd..288b425ba 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -149,7 +149,7 @@ public class ChunkUtils { } public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) { - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension bedrockDimension = session.getBedrockDimension(); int bedrockSubChunkCount = bedrockDimension.height() >> 4; byte[] payload; @@ -167,7 +167,7 @@ public class ChunkUtils { byteBuf.readBytes(payload); LevelChunkPacket data = new LevelChunkPacket(); - data.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension())); + data.setDimension(DimensionUtils.javaToBedrock(session.getBedrockDimension())); data.setChunkX(chunkX); data.setChunkZ(chunkZ); data.setSubChunksLength(0); @@ -214,7 +214,7 @@ public class ChunkUtils { throw new RuntimeException("Maximum Y must be a multiple of 16!"); } - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension bedrockDimension = session.getBedrockDimension(); // Yell in the console if the world height is too height in the current scenario // The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled // (Ignore this for the Nether. We can't change that at the moment without the workaround. :/ ) diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 821358bd8..f043631b6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -179,7 +179,7 @@ public class DimensionUtils { } public static void setBedrockDimension(GeyserSession session, int bedrockDimension) { - session.getChunkCache().setBedrockDimension(switch (bedrockDimension) { + session.setBedrockDimension(switch (bedrockDimension) { case BEDROCK_END_ID -> BedrockDimension.THE_END; case BEDROCK_DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled. default -> BedrockDimension.OVERWORLD; diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index b0bfffc19..d8c41d626 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -159,7 +159,7 @@ public class InventoryUtils { @Nullable public static Vector3i findAvailableWorldSpace(GeyserSession session) { // Check if a fake block can be placed, either above the player or beneath. - BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension dimension = session.getBedrockDimension(); int minY = dimension.minY(), maxY = minY + dimension.height(); Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt(); Vector3i position = flatPlayerPosition.add(Vector3i.UP); From 61ae5debd4527875a5dc0bff912c029f2501a1b1 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 3 Aug 2024 10:23:06 -0500 Subject: [PATCH 2/2] Allow dumps to be created even if GeyserServer failed to start (#4930) --- .../geyser/command/defaults/DumpCommand.java | 50 ++++++++++--------- .../org/geysermc/geyser/dump/DumpInfo.java | 22 ++++---- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java index 45100f525..fc46f0108 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java @@ -63,31 +63,31 @@ public class DumpCommand extends GeyserCommand { this.geyser = geyser; } - @Override - public void register(CommandManager manager) { - manager.command(baseBuilder(manager) - .optional(ARGUMENTS, stringArrayParser(), SuggestionProvider.blockingStrings((ctx, input) -> { - // parse suggestions here - List inputs = new ArrayList<>(); - while (input.hasRemainingInput()) { - inputs.add(input.readStringSkipWhitespace()); - } + @Override + public void register(CommandManager manager) { + manager.command(baseBuilder(manager) + .optional(ARGUMENTS, stringArrayParser(), SuggestionProvider.blockingStrings((ctx, input) -> { + // parse suggestions here + List inputs = new ArrayList<>(); + while (input.hasRemainingInput()) { + inputs.add(input.readStringSkipWhitespace()); + } - if (inputs.size() <= 2) { - return SUGGESTIONS; // only `geyser dump` was typed (2 literals) - } + if (inputs.size() <= 2) { + return SUGGESTIONS; // only `geyser dump` was typed (2 literals) + } - // the rest of the input after `geyser dump` is for this argument - inputs = inputs.subList(2, inputs.size()); + // the rest of the input after `geyser dump` is for this argument + inputs = inputs.subList(2, inputs.size()); - // don't suggest any words they have already typed - List suggestions = new ArrayList<>(); - SUGGESTIONS.forEach(suggestions::add); - suggestions.removeAll(inputs); - return suggestions; - })) - .handler(this::execute)); - } + // don't suggest any words they have already typed + List suggestions = new ArrayList<>(); + SUGGESTIONS.forEach(suggestions::add); + suggestions.removeAll(inputs); + return suggestions; + })) + .handler(this::execute)); + } @Override public void execute(CommandContext context) { @@ -113,13 +113,15 @@ public class DumpCommand extends GeyserCommand { source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", source.locale())); String dumpData; try { + DumpInfo dump = new DumpInfo(geyser, addLog); + if (offlineDump) { DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); // Make arrays easier to read prettyPrinter.indentArraysWith(new DefaultIndenter(" ", "\n")); - dumpData = MAPPER.writer(prettyPrinter).writeValueAsString(new DumpInfo(addLog)); + dumpData = MAPPER.writer(prettyPrinter).writeValueAsString(dump); } else { - dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog)); + dumpData = MAPPER.writeValueAsString(dump); } } catch (IOException e) { source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", source.locale())); diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 6989dc10a..515e1a629 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -81,7 +81,7 @@ public class DumpInfo { private final FlagsInfo flagsInfo; private final List extensionInfo; - public DumpInfo(boolean addLog) { + public DumpInfo(GeyserImpl geyser, boolean addLog) { this.versionInfo = new VersionInfo(); this.cpuCount = Runtime.getRuntime().availableProcessors(); @@ -91,7 +91,7 @@ public class DumpInfo { this.gitInfo = new GitInfo(GeyserImpl.BUILD_NUMBER, GeyserImpl.COMMIT.substring(0, 7), GeyserImpl.COMMIT, GeyserImpl.BRANCH, GeyserImpl.REPOSITORY); - this.config = GeyserImpl.getInstance().getConfig(); + this.config = geyser.getConfig(); this.floodgate = new Floodgate(); String md5Hash = "unknown"; @@ -107,7 +107,7 @@ public class DumpInfo { //noinspection UnstableApiUsage sha256Hash = byteSource.hash(Hashing.sha256()).toString(); } catch (Exception e) { - if (GeyserImpl.getInstance().getConfig().isDebugMode()) { + if (this.config.isDebugMode()) { e.printStackTrace(); } } @@ -116,18 +116,22 @@ public class DumpInfo { this.ramInfo = new RamInfo(); if (addLog) { - this.logsInfo = new LogsInfo(); + this.logsInfo = new LogsInfo(geyser); } this.userPlatforms = new Object2IntOpenHashMap<>(); - for (GeyserSession session : GeyserImpl.getInstance().getSessionManager().getAllSessions()) { + for (GeyserSession session : geyser.getSessionManager().getAllSessions()) { DeviceOs device = session.getClientData().getDeviceOs(); userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1); } - this.connectionAttempts = GeyserImpl.getInstance().getGeyserServer().getConnectionAttempts(); + if (geyser.getGeyserServer() != null) { + this.connectionAttempts = geyser.getGeyserServer().getConnectionAttempts(); + } else { + this.connectionAttempts = 0; // Fallback if Geyser failed to fully startup + } - this.bootstrapInfo = GeyserImpl.getInstance().getBootstrap().getDumpInfo(); + this.bootstrapInfo = geyser.getBootstrap().getDumpInfo(); this.flagsInfo = new FlagsInfo(); @@ -244,10 +248,10 @@ public class DumpInfo { public static class LogsInfo { private String link; - public LogsInfo() { + public LogsInfo(GeyserImpl geyser) { try { Map fields = new HashMap<>(); - fields.put("content", FileUtils.readAllLines(GeyserImpl.getInstance().getBootstrap().getLogsPath()).collect(Collectors.joining("\n"))); + fields.put("content", FileUtils.readAllLines(geyser.getBootstrap().getLogsPath()).collect(Collectors.joining("\n"))); JsonNode logData = GeyserImpl.JSON_MAPPER.readTree(WebUtils.postForm("https://api.mclo.gs/1/log", fields));