Skip to content
Merged

1.21.80 #5525

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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!

## Supported Versions
Geyser is currently supporting Minecraft Bedrock 1.21.50 - 1.21.72 and Minecraft Java 1.21.5. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/).
Geyser is currently supporting Minecraft Bedrock 1.21.50 - 1.21.80 and Minecraft Java 1.21.5. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/).

## Setting Up
Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser.
Expand Down
12 changes: 10 additions & 2 deletions core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,19 @@ public void tick() {

if (isPaddlingLeft) {
paddleTimeLeft += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
if (GameProtocol.is1_21_80orHigher(session)) {
dirtyMetadata.put(EntityDataTypes.ROW_TIME_LEFT, paddleTimeLeft);
} else {
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
}
}
if (isPaddlingRight) {
paddleTimeRight += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
if (GameProtocol.is1_21_80orHigher(session)) {
dirtyMetadata.put(EntityDataTypes.ROW_TIME_RIGHT, paddleTimeRight);
} else {
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,6 @@ static BedrockCodec processCodec(BedrockCodec codec) {
.updateSerializer(InventorySlotPacket.class, INVENTORY_SLOT_SERIALIZER_V748)
.updateSerializer(MovePlayerPacket.class, MOVE_PLAYER_SERIALIZER)
.updateSerializer(MoveEntityAbsolutePacket.class, MOVE_ENTITY_SERIALIZER)
.updateSerializer(RiderJumpPacket.class, ILLEGAL_SERIALIZER)
.updateSerializer(PlayerInputPacket.class, ILLEGAL_SERIALIZER)
// Ignored only when serverbound
.updateSerializer(BossEventPacket.class, bossEventSerializer)
.updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER)
Expand All @@ -303,6 +301,13 @@ static BedrockCodec processCodec(BedrockCodec codec) {
.updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER)
.updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER);

// These packets have been removed post 1.21.80.
if (codec.getProtocolVersion() < 800) {
codecBuilder
.updateSerializer(RiderJumpPacket.class, ILLEGAL_SERIALIZER)
.updateSerializer(PlayerInputPacket.class, ILLEGAL_SERIALIZER);
}

return codecBuilder.build();
}

Expand Down
21 changes: 14 additions & 7 deletions core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@

import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748;
import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766;
import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776;
import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786;
import org.cloudburstmc.protocol.bedrock.codec.v800.Bedrock_v800;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
Expand All @@ -49,8 +49,8 @@ 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 = CodecProcessor.processCodec(Bedrock_v786.CODEC.toBuilder()
.minecraftVersion("1.21.70")
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v800.CODEC.toBuilder()
.minecraftVersion("1.21.80")
.build());

/**
Expand All @@ -71,6 +71,9 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder()
.minecraftVersion("1.21.60 - 1.21.62")
.build()));
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v786.CODEC.toBuilder()
.minecraftVersion("1.21.70 - 1.21.73")
.build()));
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
}

Expand All @@ -90,10 +93,6 @@ public final class GameProtocol {

/* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */

public static boolean isPreWinterDrop(GeyserSession session) {
return session.getUpstream().getProtocolVersion() == Bedrock_v748.CODEC.getProtocolVersion();
}

public static boolean isPreCreativeInventoryRewrite(int protocolVersion) {
return protocolVersion < 776;
}
Expand All @@ -102,6 +101,14 @@ public static boolean is1_21_70orHigher(GeyserSession session) {
return session.protocolVersion() >= Bedrock_v786.CODEC.getProtocolVersion();
}

public static boolean isTheOneVersionWithBrokenForms(GeyserSession session) {
return session.protocolVersion() == Bedrock_v786.CODEC.getProtocolVersion();
}

public static boolean is1_21_80orHigher(GeyserSession session) {
return session.protocolVersion() >= Bedrock_v800.CODEC.getProtocolVersion();
}

/**
* Gets the {@link PacketCodec} for Minecraft: Java Edition.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.biome.BiomeDefinitions;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.geysermc.geyser.GeyserImpl;
Expand Down Expand Up @@ -98,9 +99,15 @@ public final class Registries {

/**
* A registry holding a NbtMap of all the known biomes.
* Remove once 1.21.80 is lowest supported version - replaced by {@link Registries#BIOMES}
*/
public static final SimpleDeferredRegistry<NbtMap> BIOMES_NBT = SimpleDeferredRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT);

/**
* A registry holding biome data for all known biomes.
*/
public static final SimpleDeferredRegistry<BiomeDefinitions> BIOMES = SimpleDeferredRegistry.create("bedrock/stripped_biome_definitions.json", RegistryLoaders.BIOME_LOADER);

/**
* A mapped registry which stores Java biome identifiers and their Bedrock biome identifier.
*/
Expand Down Expand Up @@ -200,6 +207,7 @@ public static void load() {

BEDROCK_ENTITY_IDENTIFIERS.load();
BIOMES_NBT.load();
BIOMES.load();
BIOME_IDENTIFIERS.load();
BLOCK_ENTITIES.load();
PARTICLES.load();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2025 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.registry.loader;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.cloudburstmc.protocol.bedrock.data.biome.BiomeDefinitionData;
import org.cloudburstmc.protocol.bedrock.data.biome.BiomeDefinitions;
import org.geysermc.geyser.GeyserImpl;

import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.Map;

public class BiomeLoader implements RegistryLoader<String, BiomeDefinitions> {
private final Gson GSON = new GsonBuilder()
.registerTypeAdapter(Color.class, new ColorTypeAdapter())
.create(); // temporary

@Override
public BiomeDefinitions load(String input) {
Type type = new TypeToken<Map<String, BiomeDefinitionData>>() {}.getType();
Map<String, BiomeDefinitionData> biomes;
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) {
biomes = GSON.fromJson(new InputStreamReader(stream), type);
} catch (Exception e) {
throw new AssertionError("Unable to load Bedrock biomes!", e);
}

return new BiomeDefinitions(biomes);
}

public static class ColorTypeAdapter extends TypeAdapter<Color> {

@Override
public void write(JsonWriter out, Color color) throws IOException {
if (color == null) {
out.nullValue();
return;
}

out.beginObject();
out.name("r").value(color.getRed());
out.name("g").value(color.getGreen());
out.name("b").value(color.getBlue());
out.name("a").value(color.getAlpha());
out.endObject();
}

@Override
public Color read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}

int r = 0, g = 0, b = 0, a = 255;
in.beginObject();
while (in.hasNext()) {
switch (in.nextName()) {
case "r": r = in.nextInt(); break;
case "g": g = in.nextInt(); break;
case "b": b = in.nextInt(); break;
case "a": a = in.nextInt(); break;
default: in.skipValue(); break;
}
}
in.endObject();
return new Color(r, g, b, a);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public final class RegistryLoaders {
*/
public static final NbtRegistryLoader NBT = new NbtRegistryLoader();

/**
* The {@link RegistryLoader} responsible for loading biome data.
*/
public static final BiomeLoader BIOME_LOADER = new BiomeLoader();

/**
* The {@link RegistryLoader} responsible for loading resource packs.
*/
Expand Down Expand Up @@ -69,4 +74,4 @@ public static <I, V> RegistryLoader<I, V> uninitialized() {

private RegistryLoaders() {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766;
import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776;
import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786;
import org.cloudburstmc.protocol.bedrock.codec.v800.Bedrock_v800;
import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.geysermc.geyser.GeyserImpl;
Expand Down Expand Up @@ -121,6 +122,7 @@ private static void registerBedrockBlocks() {
.put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), Conversion776_766::remapBlock)
.put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), Conversion786_776::remapBlock)
.put(ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()), tag -> tag)
.put(ObjectIntPair.of("1_21_80", Bedrock_v800.CODEC.getProtocolVersion()), tag -> tag)
.build();

// We can keep this strong as nothing should be garbage collected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766;
import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776;
import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786;
import org.cloudburstmc.protocol.bedrock.codec.v800.Bedrock_v800;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
Expand Down Expand Up @@ -129,6 +130,8 @@ public static void populate() {
paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping));
paletteVersions.add(new PaletteVersion("1_21_60", Bedrock_v776.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping));
paletteVersions.add(new PaletteVersion("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()));
// Not a typo; they're the same
paletteVersions.add(new PaletteVersion("1_21_70", Bedrock_v800.CODEC.getProtocolVersion()));

GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766;
import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776;
import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786;
import org.cloudburstmc.protocol.bedrock.codec.v800.Bedrock_v800;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.item.type.Item;
Expand Down Expand Up @@ -70,7 +71,9 @@ public boolean equals(int[] a, int[] b) {
List<ObjectIntPair<String>> paletteVersions = List.of(
ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()),
ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()),
ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion())
ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()),
// Not a typo, they're the same file
ObjectIntPair.of("1_21_70", Bedrock_v800.CODEC.getProtocolVersion())
);
Type type = new TypeToken<Map<String, List<String>>>() {}.getType();

Expand Down
13 changes: 10 additions & 3 deletions core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -786,9 +786,16 @@ public void connect() {

ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);

BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
biomeDefinitionListPacket.setDefinitions(Registries.BIOMES_NBT.get());
upstream.sendPacket(biomeDefinitionListPacket);
if (GameProtocol.is1_21_80orHigher(this)) {
BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
biomeDefinitionListPacket.setBiomes(Registries.BIOMES.get());
upstream.sendPacket(biomeDefinitionListPacket);
GeyserImpl.getInstance().getLogger().info(biomeDefinitionListPacket.toString());
} else {
BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
biomeDefinitionListPacket.setDefinitions(Registries.BIOMES_NBT.get());
upstream.sendPacket(biomeDefinitionListPacket);
}

AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket();
entityPacket.setIdentifiers(Registries.BEDROCK_ENTITY_IDENTIFIERS.get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.RequiredArgsConstructor;
import org.cloudburstmc.protocol.bedrock.packet.ModalFormRequestPacket;
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
Expand All @@ -48,6 +44,11 @@
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@RequiredArgsConstructor
public class FormCache {
private static final Gson GSON_TEMP = new Gson();
Expand Down Expand Up @@ -113,7 +114,7 @@ public void handleResponse(ModalFormResponsePacket response) {
//todo work on a proper solution in Cumulus, but that'd require all Floodgate instances to update as well and
// drops support for older Bedrock versions (because Cumulus isn't made to support multiple versions). That's
// why this hotfix exists.
if (form instanceof CustomForm customForm && GameProtocol.is1_21_70orHigher(session)) {
if (form instanceof CustomForm customForm && GameProtocol.isTheOneVersionWithBrokenForms(session) && response.getCancelReason().isEmpty()) {
// Labels are no longer included as a json null, so we have to manually add them for now.
IntList labelIndexes = new IntArrayList();
for (int i = 0; i < customForm.content().size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public void translate(GeyserSession session, PlayerAuthInputPacket packet) {
// Only set steering values when the vehicle is a boat and when the client is actually in it
if (entity.getVehicle() instanceof BoatEntity && inputData.contains(PlayerAuthInputData.IN_CLIENT_PREDICTED_IN_VEHICLE)) {
boolean up = inputData.contains(PlayerAuthInputData.UP);
// Yes. These are flipped. It's always been an issue with Geyser. That's what it's like working with this codebase.
// Yes. These are flipped. Welcome to Bedrock edition.
// Hi random stranger. I am six days into updating for 1.21.3. How's it going?
session.setSteeringLeft(up || inputData.contains(PlayerAuthInputData.PADDLE_RIGHT));
session.setSteeringRight(up || inputData.contains(PlayerAuthInputData.PADDLE_LEFT));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void translate(GeyserSession session, ClientboundSetPassengersPacket pack
if (passenger == session.getPlayerEntity()) {
session.getPlayerEntity().setVehicle(entity);
// We need to confirm teleports before entering a vehicle, or else we will likely exit right out
session.confirmTeleport(passenger.getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0).toDouble());
session.confirmTeleport(passenger.getPosition().down(EntityDefinitions.PLAYER.offset()).toDouble());

if (entity instanceof ClientVehicle clientVehicle) {
clientVehicle.getVehicleComponent().onMount();
Expand Down
Binary file not shown.
Loading