diff --git a/HiderCore/src/de/steamwar/techhider/ChunkHider.java b/HiderCore/src/de/steamwar/techhider/ChunkHider.java index 6cabee7b..ab4eb45e 100644 --- a/HiderCore/src/de/steamwar/techhider/ChunkHider.java +++ b/HiderCore/src/de/steamwar/techhider/ChunkHider.java @@ -23,6 +23,7 @@ import de.steamwar.core.ProtocolUtils; import de.steamwar.techhider.AccessPrivilegeProvider.ForPlayer; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.util.SimpleBitStorage; @@ -31,6 +32,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.UnaryOperator; @@ -263,21 +265,30 @@ public class ChunkHider { private List filterBlockEntities(ForPlayer access, List blockEntities, int chunkX, int chunkZ) { int fourBitBitmask = 0b0000_1111; - return blockEntities.stream() - .filter((blockEntityInfo) -> { - BlockEntityType type = blockEntityInfo.type; - int packedXZ = blockEntityInfo.packedXZ; + List filtered = new ArrayList<>(blockEntities.size()); + for (ClientboundLevelChunkPacketData.BlockEntityInfo blockEntityInfo : blockEntities) { + BlockEntityType type = blockEntityInfo.type; + int packedXZ = blockEntityInfo.packedXZ; - int localX = (packedXZ >> 4) & fourBitBitmask; - int localZ = packedXZ & fourBitBitmask; + int localX = (packedXZ >> 4) & fourBitBitmask; + int localZ = packedXZ & fourBitBitmask; - int worldX = (chunkX * SECTION_SPAN_SIZE) + localX; - int worldZ = (chunkZ * SECTION_SPAN_SIZE) + localZ; + int worldX = (chunkX * SECTION_SPAN_SIZE) + localX; + int worldZ = (chunkZ * SECTION_SPAN_SIZE) + localZ; - int worldY = blockEntityInfo.y; + int worldY = blockEntityInfo.y; - return access.canAccessPosition(worldX, worldY, worldZ) && access.canAccessBlockEntity(worldX, worldY, worldZ, type); - }).toList(); + // A hidden position is obfuscated as a whole + if (!access.canAccessPosition(worldX, worldY, worldZ)) continue; + + if (access.canAccessBlockEntity(worldX, worldY, worldZ, type)) { + filtered.add(blockEntityInfo); + } else { + // Without its block entity, the client would not render blocks like shulker boxes, so only their data is hidden + filtered.add(new ClientboundLevelChunkPacketData.BlockEntityInfo(packedXZ, worldY, type, new CompoundTag())); + } + } + return filtered; } private void copyOverSectionBiomeData(ByteBuf oldData, ByteBuf newData) { diff --git a/HiderCore/src/hidercore.accesswidener b/HiderCore/src/hidercore.accesswidener index 347067a1..9a266fac 100644 --- a/HiderCore/src/hidercore.accesswidener +++ b/HiderCore/src/hidercore.accesswidener @@ -25,3 +25,4 @@ accessible class net/minecraft/network/protocol/game/ClientboundLevelChunkPacket accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo type Lnet/minecraft/world/level/block/entity/BlockEntityType; accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo packedXZ I accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo y I +accessible method net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo (IILnet/minecraft/world/level/block/entity/BlockEntityType;Lnet/minecraft/nbt/CompoundTag;)V