mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Gracefully handle invalid block entity types
This commit is contained in:
parent
295e71627b
commit
75d1a6364c
4 changed files with 26 additions and 26 deletions
|
@ -155,7 +155,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.GeyserMC</groupId>
|
<groupId>com.github.GeyserMC</groupId>
|
||||||
<artifactId>MCProtocolLib</artifactId>
|
<artifactId>MCProtocolLib</artifactId>
|
||||||
<version>ed29b72</version>
|
<version>6edba11</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
|
|
|
@ -35,7 +35,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||||
@Override
|
@Override
|
||||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||||
if (tag.size() < 5) {
|
if (tag == null || tag.size() < 5) {
|
||||||
return; // These values aren't here
|
return; // These values aren't here
|
||||||
}
|
}
|
||||||
// Java infers from the block state, but Bedrock needs it in the tag
|
// Java infers from the block state, but Bedrock needs it in the tag
|
||||||
|
|
|
@ -46,7 +46,11 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundBlockEntityDataPacket packet) {
|
public void translate(GeyserSession session, ClientboundBlockEntityDataPacket packet) {
|
||||||
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(packet.getType());
|
final BlockEntityType type = packet.getType();
|
||||||
|
if (type == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(type);
|
||||||
// The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies
|
// The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies
|
||||||
// between Java block states and Bedrock block entity data
|
// between Java block states and Bedrock block entity data
|
||||||
int blockState;
|
int blockState;
|
||||||
|
@ -57,7 +61,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
|
||||||
}
|
}
|
||||||
|
|
||||||
Position position = packet.getPosition();
|
Position position = packet.getPosition();
|
||||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(packet.getType(), position.getX(), position.getY(), position.getZ(),
|
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(type, position.getX(), position.getY(), position.getZ(),
|
||||||
packet.getNbt(), blockState), packet.getPosition());
|
packet.getNbt(), blockState), packet.getPosition());
|
||||||
// Check for custom skulls.
|
// Check for custom skulls.
|
||||||
if (session.getPreferencesCache().showCustomSkulls() && packet.getNbt() != null && packet.getNbt().contains("SkullOwner")) {
|
if (session.getPreferencesCache().showCustomSkulls() && packet.getNbt() != null && packet.getNbt().contains("SkullOwner")) {
|
||||||
|
@ -66,7 +70,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
|
||||||
|
|
||||||
// If block entity is command block, OP permission level is appropriate, player is in creative mode and the NBT is not empty
|
// If block entity is command block, OP permission level is appropriate, player is in creative mode and the NBT is not empty
|
||||||
// TODO 1.18 re-test
|
// TODO 1.18 re-test
|
||||||
if (packet.getType() == BlockEntityType.COMMAND_BLOCK && session.getOpPermissionLevel() >= 2 &&
|
if (type == BlockEntityType.COMMAND_BLOCK && session.getOpPermissionLevel() >= 2 &&
|
||||||
session.getGameMode() == GameMode.CREATIVE && packet.getNbt() != null && packet.getNbt().size() > 5) {
|
session.getGameMode() == GameMode.CREATIVE && packet.getNbt() != null && packet.getNbt().size() > 5) {
|
||||||
ContainerOpenPacket openPacket = new ContainerOpenPacket();
|
ContainerOpenPacket openPacket = new ContainerOpenPacket();
|
||||||
openPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
openPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
||||||
|
|
|
@ -50,6 +50,7 @@ import io.netty.buffer.ByteBufOutputStream;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntLists;
|
import it.unimi.dsi.fastutil.ints.IntLists;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
|
@ -88,11 +89,12 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
int chunkSize = session.getChunkCache().getChunkHeightY();
|
int chunkSize = session.getChunkCache().getChunkHeightY();
|
||||||
int biomeGlobalPalette = session.getBiomeGlobalPalette();
|
int biomeGlobalPalette = session.getBiomeGlobalPalette();
|
||||||
|
|
||||||
// Temporarily stores compound tags of Bedrock-only block entities
|
|
||||||
List<NbtMap> bedrockOnlyBlockEntities = new ArrayList<>();
|
|
||||||
DataPalette[] javaChunks = new DataPalette[chunkSize];
|
DataPalette[] javaChunks = new DataPalette[chunkSize];
|
||||||
DataPalette[] javaBiomes = new DataPalette[chunkSize];
|
DataPalette[] javaBiomes = new DataPalette[chunkSize];
|
||||||
|
|
||||||
|
final BlockEntityInfo[] blockEntities = packet.getBlockEntities();
|
||||||
|
final List<NbtMap> bedrockBlockEntities = new ObjectArrayList<>(blockEntities.length);
|
||||||
|
|
||||||
BitSet waterloggedPaletteIds = new BitSet();
|
BitSet waterloggedPaletteIds = new BitSet();
|
||||||
BitSet pistonOrFlowerPaletteIds = new BitSet();
|
BitSet pistonOrFlowerPaletteIds = new BitSet();
|
||||||
|
|
||||||
|
@ -140,7 +142,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
|
|
||||||
// Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock
|
// Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock
|
||||||
if (BlockStateValues.getFlowerPotValues().containsKey(javaId) || BlockStateValues.getPistonValues().containsKey(javaId)) {
|
if (BlockStateValues.getFlowerPotValues().containsKey(javaId) || BlockStateValues.getPistonValues().containsKey(javaId)) {
|
||||||
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(session,
|
bedrockBlockEntities.add(BedrockOnlyBlockEntity.getTag(session,
|
||||||
Vector3i.from((packet.getX() << 4) + (yzx & 0xF), ((sectionY + yOffset) << 4) + ((yzx >> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
Vector3i.from((packet.getX() << 4) + (yzx & 0xF), ((sectionY + yOffset) << 4) + ((yzx >> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
||||||
javaId
|
javaId
|
||||||
));
|
));
|
||||||
|
@ -192,7 +194,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
||||||
int paletteId = javaData.get(yzx);
|
int paletteId = javaData.get(yzx);
|
||||||
if (pistonOrFlowerPaletteIds.get(paletteId)) {
|
if (pistonOrFlowerPaletteIds.get(paletteId)) {
|
||||||
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(session,
|
bedrockBlockEntities.add(BedrockOnlyBlockEntity.getTag(session,
|
||||||
Vector3i.from((packet.getX() << 4) + (yzx & 0xF), ((sectionY + yOffset) << 4) + ((yzx >> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
Vector3i.from((packet.getX() << 4) + (yzx & 0xF), ((sectionY + yOffset) << 4) + ((yzx >> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
||||||
javaPalette.idToState(paletteId)
|
javaPalette.idToState(paletteId)
|
||||||
));
|
));
|
||||||
|
@ -240,15 +242,16 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
|
|
||||||
session.getChunkCache().addToCache(packet.getX(), packet.getZ(), javaChunks);
|
session.getChunkCache().addToCache(packet.getX(), packet.getZ(), javaChunks);
|
||||||
|
|
||||||
BlockEntityInfo[] blockEntities = packet.getBlockEntities();
|
|
||||||
NbtMap[] bedrockBlockEntities = new NbtMap[blockEntities.length + bedrockOnlyBlockEntities.size()];
|
|
||||||
int blockEntityCount = 0;
|
|
||||||
final int chunkBlockX = packet.getX() << 4;
|
final int chunkBlockX = packet.getX() << 4;
|
||||||
final int chunkBlockZ = packet.getZ() << 4;
|
final int chunkBlockZ = packet.getZ() << 4;
|
||||||
while (blockEntityCount < blockEntities.length) {
|
for (BlockEntityInfo blockEntity : blockEntities) {
|
||||||
BlockEntityInfo blockEntity = blockEntities[blockEntityCount];
|
|
||||||
CompoundTag tag = blockEntity.getNbt();
|
|
||||||
BlockEntityType type = blockEntity.getType();
|
BlockEntityType type = blockEntity.getType();
|
||||||
|
if (type == null) {
|
||||||
|
// As an example: ViaVersion will send -1 if it cannot find the block entity type
|
||||||
|
// Vanilla Minecraft gracefully handles this
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CompoundTag tag = blockEntity.getNbt();
|
||||||
int x = blockEntity.getX(); // Relative to chunk
|
int x = blockEntity.getX(); // Relative to chunk
|
||||||
int y = blockEntity.getY();
|
int y = blockEntity.getY();
|
||||||
int z = blockEntity.getZ(); // Relative to chunk
|
int z = blockEntity.getZ(); // Relative to chunk
|
||||||
|
@ -259,25 +262,18 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
|
|
||||||
if (type == BlockEntityType.LECTERN && BlockStateValues.getLecternBookStates().get(blockState)) {
|
if (type == BlockEntityType.LECTERN && BlockStateValues.getLecternBookStates().get(blockState)) {
|
||||||
// If getLecternBookStates is false, let's just treat it like a normal block entity
|
// If getLecternBookStates is false, let's just treat it like a normal block entity
|
||||||
bedrockBlockEntities[blockEntityCount++] = session.getGeyser().getWorldManager().getLecternDataAt(
|
bedrockBlockEntities.add(session.getGeyser().getWorldManager().getLecternDataAt(
|
||||||
session, x + chunkBlockX, y, z + chunkBlockZ, true);
|
session, x + chunkBlockX, y, z + chunkBlockZ, true));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(type);
|
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(type);
|
||||||
bedrockBlockEntities[blockEntityCount] = blockEntityTranslator.getBlockEntityTag(type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState);
|
bedrockBlockEntities.add(blockEntityTranslator.getBlockEntityTag(type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState));
|
||||||
|
|
||||||
// Check for custom skulls
|
// Check for custom skulls
|
||||||
if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.contains("SkullOwner")) {
|
if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.contains("SkullOwner")) {
|
||||||
SkullBlockEntityTranslator.spawnPlayer(session, tag, x + chunkBlockX, y, z + chunkBlockZ, blockState);
|
SkullBlockEntityTranslator.spawnPlayer(session, tag, x + chunkBlockX, y, z + chunkBlockZ, blockState);
|
||||||
}
|
}
|
||||||
blockEntityCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append Bedrock-exclusive block entities to output array
|
|
||||||
for (NbtMap tag : bedrockOnlyBlockEntities) {
|
|
||||||
bedrockBlockEntities[blockEntityCount] = tag;
|
|
||||||
blockEntityCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find highest section
|
// Find highest section
|
||||||
|
@ -300,7 +296,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
size += ChunkUtils.EMPTY_CHUNK_DATA.length; // Consists only of biome data
|
size += ChunkUtils.EMPTY_CHUNK_DATA.length; // Consists only of biome data
|
||||||
size += 1; // Border blocks
|
size += 1; // Border blocks
|
||||||
size += 1; // Extra data length (always 0)
|
size += 1; // Extra data length (always 0)
|
||||||
size += bedrockBlockEntities.length * 64; // Conservative estimate of 64 bytes per tile entity
|
size += bedrockBlockEntities.size() * 64; // Conservative estimate of 64 bytes per tile entity
|
||||||
|
|
||||||
// Allocate output buffer
|
// Allocate output buffer
|
||||||
byteBuf = ByteBufAllocator.DEFAULT.buffer(size);
|
byteBuf = ByteBufAllocator.DEFAULT.buffer(size);
|
||||||
|
|
Loading…
Reference in a new issue