1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

1.21.90 support (#5589)

* Initial changes for 1.21.90

* Update Bedrock protocol, fix camera present serializer

* yeet debug

* Set auth chain data

* Update dependencies, add bstats metrics for haproxy usage
This commit is contained in:
chris
2025-06-17 03:23:53 +02:00
committed by GitHub
parent 42ff733f2a
commit 871390b803
17 changed files with 20164 additions and 169 deletions

View File

@@ -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.82 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.90 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.

View File

@@ -113,4 +113,14 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
* @since 2.1.1
*/
public abstract boolean unregister(@NonNull UUID uuid);
/**
* Whether to forcefully disable vibrant visuals for joining clients.
* While vibrant visuals are nice to look at, they can cause issues with
* some resource packs.
*
* @param enabled Whether vibrant visuals are allowed. This is true by default.
* @since 2.7.2
*/
public abstract void allowVibrantVisuals(boolean enabled);
}

View File

@@ -479,6 +479,8 @@ public class GeyserImpl implements GeyserApi, EventRegistrar {
metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::platformName));
metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserImpl.VERSION));
metrics.addCustomChart(new Metrics.SimplePie("javaHaProxyProtocol", () -> String.valueOf(config.getRemote().isUseProxyProtocol())));
metrics.addCustomChart(new Metrics.SimplePie("bedrockHaProxyProtocol", () -> String.valueOf(config.getBedrock().isEnableProxyProtocol())));
metrics.addCustomChart(new Metrics.AdvancedPie("playerPlatform", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (GeyserSession session : sessionManager.getAllSessions()) {

View File

@@ -70,8 +70,11 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
*/
private final Map<UUID, OptionHolder> sessionPackOptionOverrides;
private final GeyserSession session;
public SessionLoadResourcePacksEventImpl(GeyserSession session) {
super(session);
this.session = session;
this.packs = new Object2ObjectLinkedOpenHashMap<>(Registries.RESOURCE_PACKS.get());
this.sessionPackOptionOverrides = new Object2ObjectOpenHashMap<>();
}
@@ -160,6 +163,11 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
return packs.remove(uuid) != null;
}
@Override
public void allowVibrantVisuals(boolean enabled) {
session.setAllowVibrantVisuals(enabled);
}
private void attemptRegisterOptions(@NonNull GeyserResourcePack pack, @Nullable ResourcePackOption<?>... options) {
if (options == null) {
return;

View File

@@ -31,6 +31,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.codec.v818.Bedrock_v818;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
@@ -49,8 +50,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_v800.CODEC.toBuilder()
.minecraftVersion("1.21.80")
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v818.CODEC.toBuilder()
.minecraftVersion("1.21.90")
.build());
/**
@@ -74,6 +75,9 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v786.CODEC.toBuilder()
.minecraftVersion("1.21.70 - 1.21.73")
.build()));
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v800.CODEC.toBuilder()
.minecraftVersion("1.21.80 - 1.21.84")
.build()));
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
}
@@ -109,6 +113,10 @@ public final class GameProtocol {
return session.protocolVersion() >= Bedrock_v800.CODEC.getProtocolVersion();
}
public static boolean is1_21_90orHigher(GeyserSession session) {
return session.protocolVersion() >= Bedrock_v818.CODEC.getProtocolVersion();
}
/**
* Gets the {@link PacketCodec} for Minecraft: Java Edition.
*

View File

@@ -208,6 +208,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
resourcePacksInfo.getResourcePackInfos().addAll(this.resourcePackLoadEvent.infoPacketEntries());
resourcePacksInfo.setVibrantVisualsForceDisabled(!session.isAllowVibrantVisuals());
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks());
resourcePacksInfo.setWorldTemplateId(UUID.randomUUID());
@@ -241,7 +242,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
stackPacket.setGameVersion(session.getClientData().getGameVersion());
stackPacket.getResourcePacks().addAll(this.resourcePackLoadEvent.orderedPacks());
// Allows Vibrant Visuals to be toggled in the settings
stackPacket.getExperiments().add(new ExperimentData("experimental_graphics", true));
if (session.isAllowVibrantVisuals() && !GameProtocol.is1_21_90orHigher(session)) {
stackPacket.getExperiments().add(new ExperimentData("experimental_graphics", true));
}
session.sendUpstreamPacket(stackPacket);
}

View File

@@ -37,6 +37,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.codec.v818.Bedrock_v818;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.item.type.Item;
@@ -73,7 +74,8 @@ public final class TagRegistryPopulator {
ObjectIntPair.of("1_21_60", Bedrock_v776.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())
ObjectIntPair.of("1_21_70", Bedrock_v800.CODEC.getProtocolVersion()),
ObjectIntPair.of("1_21_70", Bedrock_v818.CODEC.getProtocolVersion())
);
Type type = new TypeToken<Map<String, List<String>>>() {}.getType();

View File

@@ -689,6 +689,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
@Setter
private int stepTicks = 0;
@Setter
private boolean allowVibrantVisuals = true;
public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop tickEventLoop) {
this.geyser = geyser;
this.upstream = new UpstreamSession(bedrockServerSession);
@@ -1620,7 +1623,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
// Needed for certain molang queries used in blocks and items
startGamePacket.getExperiments().add(new ExperimentData("experimental_molang_features", true));
// Allows Vibrant Visuals to appear in the settings menu
startGamePacket.getExperiments().add(new ExperimentData("experimental_graphics", true));
if (allowVibrantVisuals && !GameProtocol.is1_21_90orHigher(this)) {
startGamePacket.getExperiments().add(new ExperimentData("experimental_graphics", true));
}
startGamePacket.setVanillaVersion("*");
startGamePacket.setInventoriesServerAuthoritative(true);
@@ -1638,6 +1643,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.setServerId("");
startGamePacket.setWorldId("");
startGamePacket.setScenarioId("");
startGamePacket.setOwnerId("");
upstream.sendPacket(startGamePacket);
}
@@ -1680,7 +1686,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
/**
* Queue a packet to be sent to player.
*
* @param packet the bedrock packet from the NukkitX protocol lib
* @param packet the bedrock packet from the Cloudburst protocol lib
*/
public void sendUpstreamPacket(BedrockPacket packet) {
upstream.sendPacket(packet);
@@ -1689,7 +1695,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
/**
* Send a packet immediately to the player.
*
* @param packet the bedrock packet from the NukkitX protocol lib
* @param packet the bedrock packet from the Cloudburst protocol lib
*/
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
upstream.sendPacketImmediately(packet);

View File

@@ -29,6 +29,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.raphimc.minecraftauth.step.msa.StepMsaDeviceCode;
import org.cloudburstmc.protocol.bedrock.data.auth.AuthPayload;
import org.cloudburstmc.protocol.bedrock.data.auth.CertificateChainPayload;
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
import org.cloudburstmc.protocol.bedrock.packet.ServerToClientHandshakePacket;
import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult;
@@ -58,14 +60,14 @@ public class LoginEncryptionUtils {
private static boolean HAS_SENT_ENCRYPTION_MESSAGE = false;
public static void encryptPlayerConnection(GeyserSession session, LoginPacket loginPacket) {
encryptConnectionWithCert(session, loginPacket.getExtra(), loginPacket.getChain());
encryptConnectionWithCert(session, loginPacket.getAuthPayload(), loginPacket.getClientJwt());
}
private static void encryptConnectionWithCert(GeyserSession session, String clientData, List<String> certChainData) {
private static void encryptConnectionWithCert(GeyserSession session, AuthPayload authPayload, String jwt) {
try {
GeyserImpl geyser = session.getGeyser();
ChainValidationResult result = EncryptionUtils.validateChain(certChainData);
ChainValidationResult result = EncryptionUtils.validatePayload(authPayload);
geyser.getLogger().debug(String.format("Is player data signed? %s", result.signed()));
@@ -75,19 +77,25 @@ public class LoginEncryptionUtils {
}
IdentityData extraData = result.identityClaims().extraData;
// TODO!!! identity won't persist
session.setAuthData(new AuthData(extraData.displayName, extraData.identity, extraData.xuid));
session.setCertChainData(certChainData);
if (authPayload instanceof CertificateChainPayload certificateChainPayload) {
session.setCertChainData(certificateChainPayload.getChain());
} else {
GeyserImpl.getInstance().getLogger().warning("Received new auth payload!");
session.setCertChainData(List.of());
}
PublicKey identityPublicKey = result.identityClaims().parsedIdentityPublicKey();
byte[] clientDataPayload = EncryptionUtils.verifyClientData(clientData, identityPublicKey);
byte[] clientDataPayload = EncryptionUtils.verifyClientData(jwt, identityPublicKey);
if (clientDataPayload == null) {
throw new IllegalStateException("Client data isn't signed by the given chain data");
}
JsonNode clientDataJson = JSON_MAPPER.readTree(clientDataPayload);
BedrockClientData data = JSON_MAPPER.convertValue(clientDataJson, BedrockClientData.class);
data.setOriginalString(clientData);
data.setOriginalString(jwt);
session.setClientData(data);
try {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -50,9 +50,9 @@
"spawns_warm_variant_frogs"
]
},
"snowy_slopes": {
"temperature": -0.3,
"downfall": 0.9,
"grove": {
"temperature": -0.2,
"downfall": 0.8,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
@@ -70,17 +70,17 @@
"id": null,
"tags": [
"mountains",
"cold",
"monster",
"overworld",
"frozen",
"grove",
"spawns_cold_variant_farm_animals",
"spawns_cold_variant_frogs",
"spawns_snow_foxes",
"spawns_white_rabbits",
"snowy_slopes",
"spawns_cold_variant_farm_animals"
"spawns_white_rabbits"
]
},
"jagged_peaks": {
"frozen_peaks": {
"temperature": -0.7,
"downfall": 0.9,
"redSporeDensity": 0.0,
@@ -103,7 +103,7 @@
"monster",
"overworld",
"frozen",
"jagged_peaks",
"frozen_peaks",
"spawns_cold_variant_farm_animals",
"spawns_cold_variant_frogs",
"spawns_snow_foxes",
@@ -338,6 +338,32 @@
"has_structure_trail_ruins"
]
},
"meadow": {
"temperature": 0.3,
"downfall": 0.8,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 166,
"r": 96,
"g": 183,
"b": 255
},
"rain": true,
"chunkGenData": null,
"id": null,
"tags": [
"mountains",
"monster",
"overworld",
"meadow",
"bee_habitat"
]
},
"jungle_mutated": {
"temperature": 0.95,
"downfall": 0.9,
@@ -365,6 +391,36 @@
"spawns_warm_variant_farm_animals"
]
},
"jagged_peaks": {
"temperature": -0.7,
"downfall": 0.9,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 166,
"r": 96,
"g": 183,
"b": 255
},
"rain": true,
"chunkGenData": null,
"id": null,
"tags": [
"mountains",
"monster",
"overworld",
"frozen",
"jagged_peaks",
"spawns_cold_variant_farm_animals",
"spawns_cold_variant_frogs",
"spawns_snow_foxes",
"spawns_white_rabbits"
]
},
"flower_forest": {
"temperature": 0.7,
"downfall": 0.8,
@@ -586,6 +642,32 @@
"spawns_warm_variant_farm_animals"
]
},
"lush_caves": {
"temperature": 0.9,
"downfall": 0.0,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 166,
"r": 96,
"g": 183,
"b": 255
},
"rain": true,
"chunkGenData": null,
"id": null,
"tags": [
"caves",
"lush_caves",
"overworld",
"monster",
"spawns_tropical_fish_at_any_height"
]
},
"deep_frozen_ocean": {
"temperature": 0.0,
"downfall": 0.5,
@@ -834,33 +916,6 @@
"spawns_cold_variant_farm_animals"
]
},
"crimson_forest": {
"temperature": 2.0,
"downfall": 0.0,
"redSporeDensity": 0.25,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 165,
"r": 144,
"g": 89,
"b": 87
},
"rain": false,
"chunkGenData": null,
"id": null,
"tags": [
"nether",
"netherwart_forest",
"crimson_forest",
"spawn_few_zombified_piglins",
"spawn_piglin",
"spawns_warm_variant_farm_animals"
]
},
"mesa": {
"temperature": 2.0,
"downfall": 0.0,
@@ -998,6 +1053,32 @@
"spawns_cold_variant_farm_animals"
]
},
"warped_forest": {
"temperature": 2.0,
"downfall": 0.0,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.25,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 165,
"r": 144,
"g": 89,
"b": 87
},
"rain": false,
"chunkGenData": null,
"id": null,
"tags": [
"nether",
"netherwart_forest",
"warped_forest",
"spawn_endermen",
"spawns_warm_variant_farm_animals"
]
},
"mesa_plateau_stone": {
"temperature": 2.0,
"downfall": 0.0,
@@ -1385,32 +1466,6 @@
"spawns_warm_variant_farm_animals"
]
},
"meadow": {
"temperature": 0.3,
"downfall": 0.8,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 166,
"r": 96,
"g": 183,
"b": 255
},
"rain": true,
"chunkGenData": null,
"id": null,
"tags": [
"mountains",
"monster",
"overworld",
"meadow",
"bee_habitat"
]
},
"jungle_hills": {
"temperature": 0.95,
"downfall": 0.9,
@@ -1467,36 +1522,6 @@
"spawns_cold_variant_farm_animals"
]
},
"frozen_peaks": {
"temperature": -0.7,
"downfall": 0.9,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 166,
"r": 96,
"g": 183,
"b": 255
},
"rain": true,
"chunkGenData": null,
"id": null,
"tags": [
"mountains",
"monster",
"overworld",
"frozen",
"frozen_peaks",
"spawns_cold_variant_farm_animals",
"spawns_cold_variant_frogs",
"spawns_snow_foxes",
"spawns_white_rabbits"
]
},
"taiga": {
"temperature": 0.25,
"downfall": 0.8,
@@ -1633,6 +1658,33 @@
"warm"
]
},
"crimson_forest": {
"temperature": 2.0,
"downfall": 0.0,
"redSporeDensity": 0.25,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 165,
"r": 144,
"g": 89,
"b": 87
},
"rain": false,
"chunkGenData": null,
"id": null,
"tags": [
"nether",
"netherwart_forest",
"crimson_forest",
"spawn_few_zombified_piglins",
"spawn_piglin",
"spawns_warm_variant_farm_animals"
]
},
"ice_plains": {
"temperature": 0.0,
"downfall": 0.5,
@@ -1958,32 +2010,6 @@
"spawns_cold_variant_frogs"
]
},
"warped_forest": {
"temperature": 2.0,
"downfall": 0.0,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.25,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 165,
"r": 144,
"g": 89,
"b": 87
},
"rain": false,
"chunkGenData": null,
"id": null,
"tags": [
"nether",
"netherwart_forest",
"warped_forest",
"spawn_endermen",
"spawns_warm_variant_farm_animals"
]
},
"mesa_plateau_stone_mutated": {
"temperature": 2.0,
"downfall": 0.0,
@@ -2037,9 +2063,9 @@
"spawns_without_patrols"
]
},
"grove": {
"temperature": -0.2,
"downfall": 0.8,
"snowy_slopes": {
"temperature": -0.3,
"downfall": 0.9,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
@@ -2057,14 +2083,14 @@
"id": null,
"tags": [
"mountains",
"cold",
"monster",
"overworld",
"grove",
"spawns_cold_variant_farm_animals",
"frozen",
"spawns_cold_variant_frogs",
"spawns_snow_foxes",
"spawns_white_rabbits"
"spawns_white_rabbits",
"snowy_slopes",
"spawns_cold_variant_farm_animals"
]
},
"warm_ocean": {
@@ -2312,32 +2338,6 @@
"overworld"
]
},
"lush_caves": {
"temperature": 0.9,
"downfall": 0.0,
"redSporeDensity": 0.0,
"blueSporeDensity": 0.0,
"ashDensity": 0.0,
"whiteAshDensity": 0.0,
"depth": 0.1,
"scale": 0.2,
"mapWaterColor": {
"a": 166,
"r": 96,
"g": 183,
"b": 255
},
"rain": true,
"chunkGenData": null,
"id": null,
"tags": [
"caves",
"lush_caves",
"overworld",
"monster",
"spawns_tropical_fish_at_any_height"
]
},
"frozen_ocean": {
"temperature": 0.0,
"downfall": 0.5,

View File

@@ -8,5 +8,5 @@ org.gradle.vfs.watch=false
group=org.geysermc
id=geyser
version=2.7.1-SNAPSHOT
version=2.7.2-SNAPSHOT
description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers.

View File

@@ -9,9 +9,9 @@ netty = "4.2.1.Final"
guava = "29.0-jre"
gson = "2.3.1" # Provided by Spigot 1.8.8
websocket = "1.5.1"
protocol-connection = "3.0.0.Beta6-20250506.012145-17"
protocol-common = "3.0.0.Beta6-20250506.012145-17"
protocol-codec = "3.0.0.Beta6-20250506.012145-17"
protocol-connection = "3.0.0.Beta7-20250616.124609-6"
protocol-common = "3.0.0.Beta7-20250616.124609-6"
protocol-codec = "3.0.0.Beta7-20250616.124609-6"
raknet = "1.0.0.CR3-20250218.160705-18"
minecraftauth = "4.1.1"
mcprotocollib = "1.21.5-20250509.144049-29"