From 23ed0b68b39dbd333c5f79f048e6ca6ed71b9279 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 23 Jan 2021 20:12:10 -0500 Subject: [PATCH 1/2] Send client render distance value to server --- .../network/session/GeyserSession.java | 23 ++++++++++ .../BedrockRequestChunkRadiusTranslator.java | 46 +++++++++++++++++++ .../java/JavaJoinGameTranslator.java | 13 +----- 3 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRequestChunkRadiusTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 104e72cd365..a860a2e0278 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -36,9 +36,13 @@ import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; +import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; +import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.ClientSettingsPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket; @@ -268,6 +272,14 @@ public class GeyserSession implements CommandSender { */ private boolean daylightCycle = true; + /** + * Stores the client render distance. + * + * At this time, it is not used to change the amount of chunks rendered. + */ + @Getter @Setter + private int clientRenderDistance; + private boolean reducedDebugInfo = false; @Setter @@ -1034,6 +1046,17 @@ public void sendAdventureSettings() { sendUpstreamPacket(adventureSettingsPacket); } + /** + * Send a ClientSettingsPacket to the server to indicate client render distance, locale, skin parts, and hand preference. + */ + public void sendJavaClientSettings() { + // We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc + List skinParts = Arrays.asList(SkinPart.values()); + ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(getLocale(), (byte) clientRenderDistance, + ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND); + sendDownstreamPacket(clientSettingsPacket); + } + /** * Used for updating statistic values since we only get changes from the server * diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRequestChunkRadiusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRequestChunkRadiusTranslator.java new file mode 100644 index 00000000000..04e7fd90baa --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRequestChunkRadiusTranslator.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2021 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.connector.network.translators.bedrock; + +import com.nukkitx.protocol.bedrock.packet.RequestChunkRadiusPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +@Translator(packet = RequestChunkRadiusPacket.class) +public class BedrockRequestChunkRadiusTranslator extends PacketTranslator { + + @Override + public void translate(RequestChunkRadiusPacket packet, GeyserSession session) { + // Circle to square + session.setClientRenderDistance(packet.getRadius()); + + if (session.isLoggedIn()) { + // Render distance was changed in-game + session.sendJavaClientSettings(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java index e9a1901dce2..432a279da58 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java @@ -25,11 +25,7 @@ package org.geysermc.connector.network.translators.java; -import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; -import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; -import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.ClientSettingsPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; import com.nukkitx.protocol.bedrock.data.GameRuleData; import com.nukkitx.protocol.bedrock.data.PlayerPermission; @@ -41,9 +37,6 @@ import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.PluginMessageUtils; -import java.util.Arrays; -import java.util.List; - @Translator(packet = ServerJoinGamePacket.class) public class JavaJoinGameTranslator extends PacketTranslator { @@ -88,11 +81,7 @@ public void translate(ServerJoinGamePacket packet, GeyserSession session) { session.setRenderDistance(packet.getViewDistance()); - // We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc - String locale = session.getLocale(); - List skinParts = Arrays.asList(SkinPart.values()); - ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND); - session.sendDownstreamPacket(clientSettingsPacket); + session.sendJavaClientSettings(); session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData())); From 3ea1459a814d81b639b1de9906a2ca60e2f06d5f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 20 Apr 2021 12:42:27 -0400 Subject: [PATCH 2/2] Fix server switching with 'large' render distances See the attached comment in DimensionUtils for more information. --- .../bedrock/BedrockRespawnTranslator.java | 2 +- .../JavaPlayerPositionRotationTranslator.java | 8 +++++++ .../connector/utils/DimensionUtils.java | 21 +++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java index 2964bd65c25..c5af3a8011a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java @@ -54,7 +54,7 @@ public void translate(RespawnPacket packet, GeyserSession session) { if (session.isSpawned()) { // Client might be stuck; resend spawn information PlayerEntity entity = session.getPlayerEntity(); - if (entity == null) return; + SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); entityDataPacket.getMetadata().putAll(entity.getMetadata()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java index b379443e3d5..b4b906622f9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import com.nukkitx.protocol.bedrock.packet.RespawnPacket; import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; @@ -81,6 +82,13 @@ public void translate(ServerPlayerPositionRotationPacket packet, GeyserSession s ChunkUtils.updateChunkPosition(session, pos.toInt()); + if (session.getRenderDistance() > 47) { + // See DimensionUtils for an explanation + ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); + chunkRadiusUpdatedPacket.setRadius(session.getRenderDistance()); + session.sendUpstreamPacket(chunkRadiusUpdatedPacket); + } + session.getConnector().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.entity.player.spawn", packet.getX(), packet.getY(), packet.getZ())); return; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index e002162c333..74097733b5f 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -28,8 +28,10 @@ import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.ChangeDimensionPacket; +import com.nukkitx.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; import com.nukkitx.protocol.bedrock.packet.MobEffectPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.connector.GeyserConnector; @@ -63,6 +65,20 @@ public static void switchDimension(GeyserSession session, String javaDimension) session.getLecternCache().clear(); session.getSkullCache().clear(); + if (session.getRenderDistance() > 47) { + // The server-sided view distance wasn't a thing until Minecraft Java 1.14 + // So ViaVersion compensates by sending a "view distance" of 64 + // That's fine, except when the actual view distance sent from the server is five chunks + // The client locks up when switching dimensions, expecting more chunks than it's getting + // To solve this, we cap at 32 unless we know that the render distance actually exceeds 32 + // 47 is the Bedrock equivalent of 32 + session.getConnector().getLogger().debug("Applying dimension switching workaround for Bedrock render distance of " + session.getRenderDistance()); + ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); + chunkRadiusUpdatedPacket.setRadius(47); + session.sendUpstreamPacket(chunkRadiusUpdatedPacket); + // Will be re-adjusted on spawn + } + Vector3i pos = Vector3i.from(0, Short.MAX_VALUE, 0); ChangeDimensionPacket changeDimensionPacket = new ChangeDimensionPacket(); @@ -125,8 +141,9 @@ public static String getNewDimension(CompoundTag dimensionTag) { GeyserConnector.getInstance().getLogger().debug("Dimension tag was null or empty."); return OVERWORLD; } - if (dimensionTag.getValue().get("effects") != null) { - return ((StringTag) dimensionTag.getValue().get("effects")).getValue(); + Tag effectsTag = dimensionTag.getValue().get("effects"); + if (effectsTag instanceof StringTag) { + return ((StringTag) effectsTag).getValue(); } GeyserConnector.getInstance().getLogger().debug("Effects portion of the tag was null or empty."); return OVERWORLD;