Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.20.80 Support and Protocol Changes #4561

Merged
merged 37 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
070a19a
Make evil more harder
Kas-tle Apr 8, 2024
65b23f3
Deregister more unused packets
Kas-tle Apr 8, 2024
3dc213a
Add more unused packets
Kas-tle Apr 8, 2024
4bad652
Pin protocol to 68dc192
Kas-tle Apr 8, 2024
1d9dd8e
Correction
Kas-tle Apr 8, 2024
92d4642
Update Protocol
Kas-tle Apr 8, 2024
decce7c
More kicking
Kas-tle Apr 10, 2024
94d2cbc
stop reading when there is no item to read (#9)
onebeastchris Apr 10, 2024
aa4306c
Bump protocol
Kas-tle Apr 11, 2024
42f2a4b
1.20.80
Kas-tle Apr 12, 2024
ddd47b6
Merge remote-tracking branch 'upstream/master' into fix/protocol
Kas-tle Apr 12, 2024
5e78331
Remove unused postinitchannel GeyserServerInitializer
Kas-tle Apr 12, 2024
4e6970c
Merge branch 'GeyserMC:master' into fix/protocol
Kas-tle Apr 12, 2024
7e25e2e
Pull protocol jitpack from cloudburst again
Kas-tle Apr 12, 2024
dff08aa
Actually builds
Kas-tle Apr 13, 2024
f200df3
Merge branch 'GeyserMC:master' into fix/protocol
Kas-tle Apr 15, 2024
9fe3207
Merge remote-tracking branch 'upstream/master' into fix/protocol
Kas-tle Apr 17, 2024
4fa183e
Merge branch 'GeyserMC:master' into fix/protocol
Kas-tle Apr 18, 2024
a65738b
Merge branch 'GeyserMC:master' into fix/protocol
Kas-tle Apr 18, 2024
42dd315
Merge branch 'GeyserMC:master' into fix/protocol
Kas-tle Apr 19, 2024
5c3c178
Bump protocol to fix BossEventPacket & EmotePacket
Kas-tle Apr 20, 2024
85c5682
Add remove before merge comment
Kas-tle Apr 20, 2024
5636c7e
Merge remote-tracking branch 'upstream/master' into fix/protocol
Kas-tle Apr 20, 2024
2b5afa1
Bump protocol to fix BlockEntityDataPacket and ignore serverbound Bos…
Kas-tle Apr 20, 2024
319beb3
Bump protocol & add more illegal/ignored packets
Kas-tle Apr 21, 2024
fe26035
Merge remote-tracking branch 'upstream/master' into fix/protocol
Kas-tle Apr 21, 2024
8c2c566
Remove deprecated packet
Kas-tle Apr 21, 2024
66419a1
Ignore ClientCacheStatusPacket instead of disallow
Kas-tle Apr 21, 2024
ca76523
Define static serializers
Kas-tle Apr 21, 2024
c089ae4
Less static class nonsense more correct order
Kas-tle Apr 21, 2024
b5bfc89
Remove unused import
Kas-tle Apr 21, 2024
c3b3550
Merge remote-tracking branch 'upstream/master' into fix/protocol
Kas-tle Apr 22, 2024
eacc89e
Bump protocol
Kas-tle Apr 22, 2024
3612cb3
Move codec processing to CodecProcessor
Kas-tle Apr 22, 2024
daf9501
Falsify recipe symetry assumption
Kas-tle Apr 22, 2024
e2df578
Update Protocol for 2 wrong packet IDs & 5 wrong directions
Kas-tle Apr 23, 2024
a07c90b
Jitpack protocol from Geyser repo
Kas-tle Apr 23, 2024
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 @@ -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.40 - 1.20.73 and Minecraft Java 1.20.4
### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.4

## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
Expand Down
127 changes: 121 additions & 6 deletions core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,34 @@
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper;
import org.cloudburstmc.protocol.bedrock.codec.v582.serializer.TrimDataSerializer_v582;
import org.cloudburstmc.protocol.bedrock.codec.BedrockPacketSerializer;
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipmentSerializer_v291;
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_v291;
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventoryContentSerializer_v407;
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventorySlotSerializer_v407;
import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622;
import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630;
import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649;
import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662;
import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.cloudburstmc.protocol.bedrock.packet.ClientCacheBlobStatusPacket;
import org.cloudburstmc.protocol.bedrock.packet.ClientCheatAbilityPacket;
import org.cloudburstmc.protocol.bedrock.packet.CraftingEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.CreatePhotoPacket;
import org.cloudburstmc.protocol.bedrock.packet.EditorNetworkPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
import org.cloudburstmc.protocol.bedrock.packet.LabTablePacket;
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.PhotoInfoRequestPacket;
import org.cloudburstmc.protocol.bedrock.packet.PhotoTransferPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
import org.cloudburstmc.protocol.bedrock.packet.PurchaseReceiptPacket;
import org.cloudburstmc.protocol.bedrock.packet.SubClientLoginPacket;
import org.cloudburstmc.protocol.common.util.VarInts;
import org.geysermc.geyser.session.GeyserSession;

import java.util.ArrayList;
Expand All @@ -52,7 +73,7 @@ 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 = processCodec(Bedrock_v662.CODEC);
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = processCodec(Bedrock_v671.CODEC);

/**
* A list of all supported Bedrock versions that can join Geyser
Expand All @@ -75,9 +96,12 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v649.CODEC.toBuilder()
.minecraftVersion("1.20.60/1.20.62")
.build()));
SUPPORTED_BEDROCK_CODECS.add(processCodec(DEFAULT_BEDROCK_CODEC.toBuilder()
SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v662.CODEC.toBuilder()
.minecraftVersion("1.20.70/1.20.73")
.build()));
SUPPORTED_BEDROCK_CODECS.add(processCodec(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.20.80")
.build()));
}

/**
Expand Down Expand Up @@ -170,14 +194,105 @@ public static String getAllSupportedJavaVersions() {

private static BedrockCodec processCodec(BedrockCodec codec) {
return codec.toBuilder()
.updateSerializer(TrimDataPacket.class, new TrimDataSerializer_v582() {
// Illegal unused serverbound EDU packets
.updateSerializer(PhotoTransferPacket.class, setIllegalSerializer())
.updateSerializer(LabTablePacket.class, setIllegalSerializer())
.updateSerializer(CreatePhotoPacket.class, setIllegalSerializer())
.updateSerializer(PhotoInfoRequestPacket.class, setIllegalSerializer())
// Illegal unused serverbound packets for featured servers
.updateSerializer(PurchaseReceiptPacket.class, setIllegalSerializer())
// Illegal unused serverbound packets for editor
.updateSerializer(EditorNetworkPacket.class, setIllegalSerializer())
// Illegal unused serverbound packets that are deprecated
.updateSerializer(ClientCheatAbilityPacket.class, setIllegalSerializer())
// Illegal unusued serverbound packets that relate to unused features
.updateSerializer(PlayerAuthInputPacket.class, setIllegalSerializer())
.updateSerializer(ClientCacheBlobStatusPacket.class, setIllegalSerializer())
.updateSerializer(SubClientLoginPacket.class, setIllegalSerializer())
// Illegal serverbound packets due to Geyser specific setup
.updateSerializer(InventoryContentPacket.class, new InventoryContentSerializer_v407() {
@Override
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) {
throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!");
}
})
.updateSerializer(InventorySlotPacket.class, new InventorySlotSerializer_v407() {
@Override
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) {
throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!");
}
})
// Ignored serverbound packets
.updateSerializer(CraftingEventPacket.class, setIgnoredSerializer()) // Make illegal when 1.20.40 is removed
// Ignored only when serverbound
.updateSerializer(MobArmorEquipmentPacket.class, new MobArmorEquipmentSerializer_v291() {
@Override
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, TrimDataPacket packet) {
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) {
}
})
// Valid serverbound packets where reading of some fields can be skipped
.updateSerializer(MobEquipmentPacket.class, new MobEquipmentSerializer_v291() {
@Override
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobEquipmentPacket packet) {
packet.setRuntimeEntityId(VarInts.readUnsignedLong(buffer));
fakeItemRead(buffer);
packet.setInventorySlot(buffer.readUnsignedByte());
packet.setHotbarSlot(buffer.readUnsignedByte());
packet.setContainerId(buffer.readByte());
}
})
.build();
}

/**
* Fake reading an item from the buffer to improve performance.
*
* @param buffer
*/
private static void fakeItemRead(ByteBuf buffer) {
int id = VarInts.readInt(buffer); // Runtime ID
if (id == 0) { // nothing more to read
return;
}
buffer.skipBytes(2); // count
VarInts.readUnsignedInt(buffer); // damage
boolean hasNetId = buffer.readBoolean();
if (hasNetId) {
VarInts.readInt(buffer);
}

VarInts.readInt(buffer); // Block runtime ID
int streamSize = VarInts.readUnsignedInt(buffer);
buffer.skipBytes(streamSize);
}

private static <T extends BedrockPacket> BedrockPacketSerializer<T> setIllegalSerializer() {
return new BedrockPacketSerializer<T>() {
@Override
public void serialize(ByteBuf buffer, BedrockCodecHelper helper, T packet) {
throw new IllegalArgumentException("Server tried to send unused packet " + packet.getClass().getSimpleName() + "!");
}

@Override
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, T packet) {
throw new IllegalArgumentException("Client tried to send unused packet " + packet.getClass().getSimpleName() + "!");
}
};
}

private static <T extends BedrockPacket> BedrockPacketSerializer<T> setIgnoredSerializer() {
return new BedrockPacketSerializer<T>() {
@Override
public void serialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) {
onebeastchris marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) {
}
};
}


private GameProtocol() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@

package org.geysermc.geyser.network;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultEventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.BedrockPeer;
import org.cloudburstmc.protocol.bedrock.BedrockServerSession;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.cloudburstmc.protocol.bedrock.netty.initializer.BedrockServerInitializer;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.event.bedrock.SessionInitializeEvent;
Expand Down Expand Up @@ -63,6 +67,10 @@ public void initSession(@NonNull BedrockServerSession bedrockServerSession) {

bedrockServerSession.setLogging(true);
GeyserSession session = new GeyserSession(this.geyser, bedrockServerSession, this.eventLoopGroup.next());

Channel channel = bedrockServerSession.getPeer().getChannel();
channel.pipeline().addAfter(BedrockPacketCodec.NAME, InvalidPacketHandler.NAME, new InvalidPacketHandler(session));

bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(this.geyser, session));
this.geyser.eventBus().fire(new SessionInitializeEvent(session));
} catch (Throwable e) {
Expand All @@ -72,6 +80,38 @@ public void initSession(@NonNull BedrockServerSession bedrockServerSession) {
}
}

@Override
protected void postInitChannel(Channel channel) throws Exception {
super.postInitChannel(channel);

channel.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
private static final int allowedExceptions = 5;
private static final long delayUntilExceptionsReset = 60;

private long lastException;
private int exceptionCounts;

@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
ctx.fireChannelRead(msg);
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
final long currentTime = System.currentTimeMillis();
if (currentTime >= lastException + (delayUntilExceptionsReset * 1000)) {
exceptionCounts = 0;
}
lastException = currentTime;
if (exceptionCounts++ > allowedExceptions) {
ctx.pipeline().get(GeyserBedrockPeer.class).close("Too many exceptions created.");
Kas-tle marked this conversation as resolved.
Show resolved Hide resolved
return;
}
super.exceptionCaught(ctx, cause);
}
});
}

@Override
protected BedrockPeer createPeer(Channel channel) {
return new GeyserBedrockPeer(channel, this::createSession);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019-2024 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.network;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.RequiredArgsConstructor;
import org.geysermc.geyser.session.GeyserSession;

import java.util.stream.Stream;

@RequiredArgsConstructor
public class InvalidPacketHandler extends ChannelInboundHandlerAdapter {
public static final String NAME = "rak-error-handler";

private final GeyserSession session;

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Throwable rootCause = Stream.iterate(cause, Throwable::getCause)
.filter(element -> element.getCause() == null)
.findFirst()
.orElse(cause);


if (!(rootCause instanceof IllegalArgumentException)) {
super.exceptionCaught(ctx, cause);
return;
}

// Kick users that try to send illegal packets
session.getGeyser().getLogger().warning(rootCause.getMessage());
session.disconnect("Invalid packet received!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
import java.util.function.Supplier;

import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_GLOBAL_PACKET_LIMIT;
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_OFFLINE_PACKET_LIMIT;
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_PACKET_LIMIT;

public final class GeyserServer {
Expand Down Expand Up @@ -217,11 +216,6 @@ private ServerBootstrap createBootstrap() {
int rakPacketLimit = positivePropOrDefault("Geyser.RakPacketLimit", DEFAULT_PACKET_LIMIT);
this.geyser.getLogger().debug("Setting RakNet packet limit to " + rakPacketLimit);

boolean isWhitelistedProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol()
&& !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty();
int rakOfflinePacketLimit = positivePropOrDefault("Geyser.RakOfflinePacketLimit", isWhitelistedProxyProtocol ? Integer.MAX_VALUE : DEFAULT_OFFLINE_PACKET_LIMIT);
this.geyser.getLogger().debug("Setting RakNet offline packet limit to " + rakOfflinePacketLimit);

int rakGlobalPacketLimit = positivePropOrDefault("Geyser.RakGlobalPacketLimit", DEFAULT_GLOBAL_PACKET_LIMIT);
this.geyser.getLogger().debug("Setting RakNet global packet limit to " + rakGlobalPacketLimit);

Expand All @@ -231,7 +225,6 @@ private ServerBootstrap createBootstrap() {
.option(RakChannelOption.RAK_HANDLE_PING, true)
.option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu())
.option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit)
.option(RakChannelOption.RAK_OFFLINE_PACKET_LIMIT, rakOfflinePacketLimit)
.option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit)
.childHandler(serverInitializer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630;
import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649;
import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662;
import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671;
import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.geysermc.geyser.GeyserImpl;
Expand Down Expand Up @@ -122,7 +123,8 @@ private static void registerBedrockBlocks() {
.put(ObjectIntPair.of("1_20_50", Bedrock_v630.CODEC.getProtocolVersion()), Conversion649_630::remapBlock)
// Only changes in 1.20.60 are hard_stained_glass (an EDU only block)
.put(ObjectIntPair.of("1_20_60", Bedrock_v649.CODEC.getProtocolVersion()), Conversion662_649::remapBlock)
.put(ObjectIntPair.of("1_20_70", Bedrock_v662.CODEC.getProtocolVersion()), tag -> tag)
.put(ObjectIntPair.of("1_20_70", Bedrock_v662.CODEC.getProtocolVersion()), Conversion671_662::remapBlock)
.put(ObjectIntPair.of("1_20_80", Bedrock_v671.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 @@ -44,6 +44,8 @@ public class Conversion662_649 {


static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) {
mapping = Conversion671_662.remapItem(item, mapping);

String identifer = mapping.getBedrockIdentifier();

if (identifer.equals("minecraft:grass_block")) {
Expand Down Expand Up @@ -93,6 +95,8 @@ static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, Geyser
}

static NbtMap remapBlock(NbtMap tag) {
tag = Conversion671_662.remapBlock(tag);

final String name = tag.getString("name");

if (!NEW_BLOCKS.contains(name)) {
Expand Down
Loading
Loading