Skip to content

Commit

Permalink
Support Java 1.20.2 (#4112)
Browse files Browse the repository at this point in the history
* Initial pass for 1.20.2, compiling
* Remove unused level events
* handle null GameProfile in ClientboundPlayerInfoUpdatePacket
* Handle level events BRUSH_BLOCK_COMPLETE and EGG_CRACK
* Account for null tag in DecoratedPotBlockEntityTranslator
* Explicitly show that 1.20.31 is supported
  • Loading branch information
Konicai authored Sep 29, 2023
1 parent 5276a1e commit c2cd99c
Show file tree
Hide file tree
Showing 28 changed files with 242 additions and 166 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t

Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!

### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.30 and Minecraft Java 1.20/1.20.1.
### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.31 and Minecraft Java 1.20/1.20.1.

## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
Expand Down
1 change: 0 additions & 1 deletion core/src/main/java/org/geysermc/geyser/GeyserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
import org.geysermc.geyser.network.netty.GeyserServer;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ public String getId() {
return this.advancement.getId();
}

@NonNull
public List<String> getCriteria() {
return this.advancement.getCriteria();
}

@NonNull
public List<List<String>> getRequirements() {
return this.advancement.getRequirements();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public final class GameProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports.
*/
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v618.CODEC;
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v618.CODEC.toBuilder()
.minecraftVersion("1.20.31")
.build();

/**
* A list of all supported Bedrock versions that can join Geyser
Expand All @@ -66,7 +68,9 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v594.CODEC.toBuilder()
.minecraftVersion("1.20.10/1.20.15")
.build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.20.30/1.20.31")
.build());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundTabListPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket;
import io.netty.channel.EventLoop;
import org.geysermc.geyser.GeyserImpl;
Expand All @@ -43,9 +44,10 @@ public class PacketTranslatorRegistry<T> extends AbstractMappedRegistry<Class<?
private static final Set<Class<?>> IGNORED_PACKETS = Collections.newSetFromMap(new IdentityHashMap<>());

static {
IGNORED_PACKETS.add(ClientboundChunkBatchStartPacket.class); // we don't track chunk batch sizes/periods
IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs
IGNORED_PACKETS.add(ClientboundLightUpdatePacket.class); // Light is handled on Bedrock for us
IGNORED_PACKETS.add(ClientboundTabListPacket.class); // Cant be implemented in Bedrock
IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs
}

protected PacketTranslatorRegistry() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@
import com.github.steveice10.mc.protocol.data.game.setting.SkinPart;
import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
Expand Down Expand Up @@ -292,7 +292,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
private Vector2i lastChunkPosition = null;
@Setter
private int clientRenderDistance = -1;
private int serverRenderDistance;
private int serverRenderDistance = -1;

// Exposed for GeyserConnect usage
protected boolean sentSpawnPacket;
Expand Down Expand Up @@ -1665,7 +1665,8 @@ public void sendDownstreamPacket(Packet packet) {
}

private void sendDownstreamPacket0(Packet packet) {
if (protocol.getState().equals(ProtocolState.GAME) || packet.getClass() == ServerboundCustomQueryPacket.class) {
ProtocolState state = protocol.getState();
if (state == ProtocolState.GAME || state == ProtocolState.CONFIGURATION || packet.getClass() == ServerboundCustomQueryAnswerPacket.class) {
downstream.sendPacket(packet);
} else {
geyser.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
Expand Down Expand Up @@ -1824,8 +1825,11 @@ private int getRenderDistance() {
if (clientRenderDistance != -1) {
// The client has sent a render distance
return clientRenderDistance;
} else if (serverRenderDistance != -1) {
// only known once ClientboundLoginPacket is received
return serverRenderDistance;
}
return serverRenderDistance;
return 2; // unfortunate default until we got more info
}

// We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@

package org.geysermc.geyser.session.cache;

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket;
import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntLists;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.type.Item;
Expand Down Expand Up @@ -112,7 +113,7 @@ public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet
}
}

private IntList load(int[] tags) {
private IntList load(int @Nullable[] tags) {
if (tags == null) {
return IntLists.EMPTY_LIST;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator {

@Override
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
if (tag == null) {
return;
}

// exact same format
if (tag.get("sherds") instanceof ListTag sherds) {
List<String> translated = new ArrayList<>(4);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

package org.geysermc.geyser.translator.protocol.bedrock;

import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundKeepAlivePacket;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundKeepAlivePacket;
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@

package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import com.google.common.base.Charsets;
import org.cloudburstmc.protocol.bedrock.packet.TransferPacket;
import org.cloudburstmc.protocol.bedrock.packet.UnknownPacket;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
Expand All @@ -41,7 +41,7 @@ public void translate(GeyserSession session, ClientboundCustomQueryPacket packet
// A vanilla client doesn't know any PluginMessage in the Login state, so we don't know any either.
// Note: Fabric Networking API v1 will not let the client log in without sending this
session.sendDownstreamPacket(
new ServerboundCustomQueryPacket(packet.getMessageId(), null)
new ServerboundCustomQueryAnswerPacket(packet.getMessageId(), null)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisconnectPacket;
import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundDisconnectPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,19 @@
package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundGameProfilePacket;
import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.PluginMessageUtils;

/**
* ClientboundGameProfilePacket triggers protocol change LOGIN -> CONFIGURATION
*/
@Translator(packet = ClientboundGameProfilePacket.class)
public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameProfilePacket> {

Expand Down Expand Up @@ -65,5 +70,9 @@ public void translate(GeyserSession session, ClientboundGameProfilePacket packet
// We no longer need these variables; they're just taking up space in memory now
session.setCertChainData(null);
session.getClientData().setOriginalString(null);

// configuration phase stuff that the vanilla client replies with after receiving the GameProfilePacket
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
session.sendJavaClientSettings();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundKeepAlivePacket;
import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundKeepAlivePacket;
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,22 @@

package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import org.cloudburstmc.protocol.bedrock.data.GameRuleData;
import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.JavaCodecUtil;
import org.geysermc.geyser.util.PluginMessageUtils;

import java.util.Map;

@Translator(packet = ClientboundLoginPacket.class)
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
Expand All @@ -64,42 +55,22 @@ public void translate(GeyserSession session, ClientboundLoginPacket packet) {
session.setErosionHandler(new GeyserboundHandshakePacketHandler(session));
}

Map<String, JavaDimension> dimensions = session.getDimensions();
dimensions.clear();

JavaDimension.load(packet.getRegistry(), dimensions);

Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes();
chatTypes.clear();
for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) {
// The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
int id = ((IntTag) tag.get("id")).getValue();
CompoundTag element = tag.get("element");
CompoundTag chat = element.get("chat");
TextDecoration textDecoration = null;
if (chat != null) {
textDecoration = new TextDecoration(chat);
}
chatTypes.put(id, textDecoration);
}
PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo();

// If the player is already initialized and a join game packet is sent, they
// are swapping servers
if (session.isSpawned()) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension());
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), spawnInfo.getDimension());
DimensionUtils.switchDimension(session, fakeDim);

session.getWorldCache().removeScoreboard();
}
session.setWorldName(packet.getWorldName());
session.setWorldName(spawnInfo.getWorldName());
session.setLevels(packet.getWorldNames());

BiomeTranslator.loadServerBiomes(session, packet.getRegistry());
session.getTagCache().clear();
session.setGameMode(spawnInfo.getGameMode());

session.setGameMode(packet.getGameMode());

String newDimension = packet.getDimension();
String newDimension = spawnInfo.getDimension();

boolean needsSpawnPacket = !session.isSentSpawnPacket();
if (needsSpawnPacket) {
Expand All @@ -114,11 +85,11 @@ public void translate(GeyserSession session, ClientboundLoginPacket packet) {

if (!needsSpawnPacket) {
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(packet.getGameMode()).ordinal());
playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(spawnInfo.getGameMode()).ordinal());
session.sendUpstreamPacket(playerGameTypePacket);
}

entity.setLastDeathPosition(packet.getLastDeathPos());
entity.setLastDeathPosition(spawnInfo.getLastDeathPos());

entity.updateBedrockMetadata();

Expand All @@ -131,16 +102,10 @@ public void translate(GeyserSession session, ClientboundLoginPacket packet) {

session.setServerRenderDistance(packet.getViewDistance());

// TODO customize
// send this again now that we know the server render distance
// as the bedrock client isn't required to send a render distance
session.sendJavaClientSettings();

session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));

// TODO don't send two packets
// if (true) {
// session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
// }
// register the plugin messaging channels used in Floodgate
if (session.remoteServer().authType() == AuthType.FLOODGATE) {
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@

package org.geysermc.geyser.translator.protocol.java;

import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPingPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundPongPacket;
import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundPingPacket;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundPongPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
Expand Down
Loading

0 comments on commit c2cd99c

Please sign in to comment.