forked from GeyserMC/Geyser
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move codec processing to CodecProcessor
Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
- Loading branch information
Showing
3 changed files
with
301 additions
and
227 deletions.
There are no files selected for viewing
292 changes: 292 additions & 0 deletions
292
core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
/* | ||
* 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.buffer.ByteBuf; | ||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; | ||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper; | ||
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.v291.serializer.PlayerHotbarSerializer_v291; | ||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.SetEntityLinkSerializer_v291; | ||
import org.cloudburstmc.protocol.bedrock.codec.v390.serializer.PlayerSkinSerializer_v390; | ||
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.v486.serializer.BossEventSerializer_v486; | ||
import org.cloudburstmc.protocol.bedrock.codec.v557.serializer.SetEntityDataSerializer_v557; | ||
import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSerializer_v662; | ||
import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.ClientCacheBlobStatusPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.ClientCacheStatusPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.ClientCheatAbilityPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.ClientToServerHandshakePacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.CodeBuilderSourcePacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.CraftingEventPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.CreatePhotoPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.DebugInfoPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.DisconnectPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.EditorNetworkPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.EntityFallPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.GameTestRequestPacket; | ||
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.MapCreateLockedCopyPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.MapInfoRequestPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.MultiplayerSettingsPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.NpcRequestPacket; | ||
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.PlayerHotbarPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.PlayerSkinPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.PurchaseReceiptPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.RefreshEntitlementsPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.ScriptMessagePacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SettingsCommandPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SimpleEventPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SubChunkRequestPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.SubClientLoginPacket; | ||
import org.cloudburstmc.protocol.bedrock.packet.TickSyncPacket; | ||
import org.cloudburstmc.protocol.common.util.VarInts; | ||
|
||
/** | ||
* Processes the Bedrock codec to remove or modify unused or unsafe packets and fields. | ||
*/ | ||
class CodecProcessor { | ||
|
||
/** | ||
* Generic serializer that throws an exception when trying to serialize or deserialize a packet, leading to client disconnection. | ||
*/ | ||
@SuppressWarnings("rawtypes") | ||
private static final BedrockPacketSerializer ILLEGAL_SERIALIZER = new BedrockPacketSerializer<>() { | ||
@Override | ||
public void serialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { | ||
throw new IllegalArgumentException("Server tried to send unused packet " + packet.getClass().getSimpleName() + "!"); | ||
} | ||
|
||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { | ||
throw new IllegalArgumentException("Client tried to send unused packet " + packet.getClass().getSimpleName() + "!"); | ||
} | ||
}; | ||
|
||
/** | ||
* Generic serializer that does nothing when trying to serialize or deserialize a packet. | ||
*/ | ||
@SuppressWarnings("rawtypes") | ||
private static final BedrockPacketSerializer IGNORED_SERIALIZER = new BedrockPacketSerializer<>() { | ||
@Override | ||
public void serialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { | ||
} | ||
|
||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that throws an exception when trying to deserialize InventoryContentPacket since server-auth inventory is used. | ||
*/ | ||
private static final BedrockPacketSerializer<InventoryContentPacket> INVENTORY_CONTENT_SERIALIZER = 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!"); | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. | ||
*/ | ||
private static final BedrockPacketSerializer<InventorySlotPacket> INVENTORY_SLOT_SERIALIZER = 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!"); | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<BossEventPacket> BOSS_EVENT_SERIALIZER = new BossEventSerializer_v486() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BossEventPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize MobArmorEquipmentPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<MobArmorEquipmentPacket> MOB_ARMOR_EQUIPMENT_SERIALIZER = new MobArmorEquipmentSerializer_v291() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize PlayerHotbarPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<PlayerHotbarPacket> PLAYER_HOTBAR_SERIALIZER = new PlayerHotbarSerializer_v291() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, PlayerHotbarPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize PlayerSkinPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<PlayerSkinPacket> PLAYER_SKIN_SERIALIZER = new PlayerSkinSerializer_v390() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, PlayerSkinPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize SetEntityDataPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<SetEntityDataPacket> SET_ENTITY_DATA_SERIALIZER = new SetEntityDataSerializer_v557() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityDataPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<SetEntityMotionPacket> SET_ENTITY_MOTION_SERIALIZER = new SetEntityMotionSerializer_v662() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that does nothing when trying to deserialize SetEntityLinkPacket since it is not used from the client. | ||
*/ | ||
private static final BedrockPacketSerializer<SetEntityLinkPacket> SET_ENTITY_LINK_SERIALIZER = new SetEntityLinkSerializer_v291() { | ||
@Override | ||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityLinkPacket packet) { | ||
} | ||
}; | ||
|
||
/** | ||
* Serializer that skips over the item when trying to deserialize MobEquipmentPacket since only the slot info is used. | ||
*/ | ||
private static final BedrockPacketSerializer<MobEquipmentPacket> MOB_EQUIPMENT_SERIALIZER = 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()); | ||
} | ||
}; | ||
|
||
@SuppressWarnings("unchecked") | ||
static BedrockCodec processCodec(BedrockCodec codec) { | ||
return codec.toBuilder() | ||
// Illegal unused serverbound EDU packets | ||
.updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(LabTablePacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(CodeBuilderSourcePacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(CreatePhotoPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(NpcRequestPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(PhotoInfoRequestPacket.class, ILLEGAL_SERIALIZER) | ||
// Illegal unused serverbound packets for featured servers | ||
.updateSerializer(PurchaseReceiptPacket.class, ILLEGAL_SERIALIZER) | ||
// Illegal unused serverbound packets that are deprecated | ||
.updateSerializer(ClientCheatAbilityPacket.class, ILLEGAL_SERIALIZER) | ||
// Illegal unusued serverbound packets that relate to unused features | ||
.updateSerializer(PlayerAuthInputPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(ClientCacheBlobStatusPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(SubClientLoginPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(SubChunkRequestPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(GameTestRequestPacket.class, ILLEGAL_SERIALIZER) | ||
// Ignored serverbound packets | ||
.updateSerializer(CraftingEventPacket.class, IGNORED_SERIALIZER) // Make illegal when 1.20.40 is removed | ||
.updateSerializer(ClientToServerHandshakePacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(EntityFallPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(MapCreateLockedCopyPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(MapInfoRequestPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(SettingsCommandPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER) | ||
// Illegal when serverbound due to Geyser specific setup | ||
.updateSerializer(InventoryContentPacket.class, INVENTORY_CONTENT_SERIALIZER) | ||
.updateSerializer(InventorySlotPacket.class, INVENTORY_SLOT_SERIALIZER) | ||
// Ignored only when serverbound | ||
.updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER) | ||
.updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER) | ||
.updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) | ||
.updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) | ||
.updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) | ||
.updateSerializer(SetEntityMotionPacket.class, SET_ENTITY_MOTION_SERIALIZER) | ||
.updateSerializer(SetEntityLinkPacket.class, SET_ENTITY_LINK_SERIALIZER) | ||
// Valid serverbound packets where reading of some fields can be skipped | ||
.updateSerializer(MobEquipmentPacket.class, MOB_EQUIPMENT_SERIALIZER) | ||
// // Illegal bidirectional packets | ||
.updateSerializer(DebugInfoPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(EditorNetworkPacket.class, ILLEGAL_SERIALIZER) | ||
.updateSerializer(ScriptMessagePacket.class, ILLEGAL_SERIALIZER) | ||
// // Ignored bidirectional packets | ||
.updateSerializer(ClientCacheStatusPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(DisconnectPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER) | ||
.updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER) | ||
.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); | ||
} | ||
} |
Oops, something went wrong.