Code/net/minecraft/network/protocol/game/ClientboundLevelChunkPacket...

166 lines
7.4 KiB
Java
Raw Permalink Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.network.protocol.game;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.Heightmap;
public class ClientboundLevelChunkPacketData {
private static final StreamCodec<ByteBuf, Map<Heightmap.Types, long[]>> HEIGHTMAPS_STREAM_CODEC = ByteBufCodecs.map(
p_389934_ -> new EnumMap<>(Heightmap.Types.class), Heightmap.Types.STREAM_CODEC, ByteBufCodecs.LONG_ARRAY
);
private static final int TWO_MEGABYTES = 2097152;
private final Map<Heightmap.Types, long[]> heightmaps;
private final byte[] buffer;
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
public ClientboundLevelChunkPacketData(LevelChunk p_195651_) {
this.heightmaps = p_195651_.getHeightmaps()
.stream()
.filter(p_389936_ -> p_389936_.getKey().sendToClient())
.collect(Collectors.toMap(Entry::getKey, p_389935_ -> (long[])p_389935_.getValue().getRawData().clone()));
this.buffer = new byte[calculateChunkSize(p_195651_)];
extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), p_195651_);
this.blockEntitiesData = Lists.newArrayList();
for (Entry<BlockPos, BlockEntity> entry : p_195651_.getBlockEntities().entrySet()) {
this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(entry.getValue()));
}
}
public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf p_335775_, int p_195654_, int p_195655_) {
this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(p_335775_);
int i = p_335775_.readVarInt();
if (i > 2097152) {
throw new RuntimeException("Chunk Packet trying to allocate too much memory on read.");
} else {
this.buffer = new byte[i];
p_335775_.readBytes(this.buffer);
this.blockEntitiesData = ClientboundLevelChunkPacketData.BlockEntityInfo.LIST_STREAM_CODEC.decode(p_335775_);
}
}
public void write(RegistryFriendlyByteBuf p_331012_) {
HEIGHTMAPS_STREAM_CODEC.encode(p_331012_, this.heightmaps);
p_331012_.writeVarInt(this.buffer.length);
p_331012_.writeBytes(this.buffer);
ClientboundLevelChunkPacketData.BlockEntityInfo.LIST_STREAM_CODEC.encode(p_331012_, this.blockEntitiesData);
}
private static int calculateChunkSize(LevelChunk p_195665_) {
int i = 0;
for (LevelChunkSection levelchunksection : p_195665_.getSections()) {
i += levelchunksection.getSerializedSize();
}
return i;
}
private ByteBuf getWriteBuffer() {
ByteBuf bytebuf = Unpooled.wrappedBuffer(this.buffer);
bytebuf.writerIndex(0);
return bytebuf;
}
public static void extractChunkData(FriendlyByteBuf p_195669_, LevelChunk p_195670_) {
for (LevelChunkSection levelchunksection : p_195670_.getSections()) {
levelchunksection.write(p_195669_);
}
}
public Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> getBlockEntitiesTagsConsumer(int p_195658_, int p_195659_) {
return p_195663_ -> this.getBlockEntitiesTags(p_195663_, p_195658_, p_195659_);
}
private void getBlockEntitiesTags(ClientboundLevelChunkPacketData.BlockEntityTagOutput p_195675_, int p_195676_, int p_195677_) {
int i = 16 * p_195676_;
int j = 16 * p_195677_;
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
for (ClientboundLevelChunkPacketData.BlockEntityInfo clientboundlevelchunkpacketdata$blockentityinfo : this.blockEntitiesData) {
int k = i + SectionPos.sectionRelative(clientboundlevelchunkpacketdata$blockentityinfo.packedXZ >> 4);
int l = j + SectionPos.sectionRelative(clientboundlevelchunkpacketdata$blockentityinfo.packedXZ);
blockpos$mutableblockpos.set(k, clientboundlevelchunkpacketdata$blockentityinfo.y, l);
p_195675_.accept(
blockpos$mutableblockpos, clientboundlevelchunkpacketdata$blockentityinfo.type, clientboundlevelchunkpacketdata$blockentityinfo.tag
);
}
}
public FriendlyByteBuf getReadBuffer() {
return new FriendlyByteBuf(Unpooled.wrappedBuffer(this.buffer));
}
public Map<Heightmap.Types, long[]> getHeightmaps() {
return this.heightmaps;
}
static class BlockEntityInfo {
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundLevelChunkPacketData.BlockEntityInfo> STREAM_CODEC = StreamCodec.ofMember(
ClientboundLevelChunkPacketData.BlockEntityInfo::write, ClientboundLevelChunkPacketData.BlockEntityInfo::new
);
public static final StreamCodec<RegistryFriendlyByteBuf, List<ClientboundLevelChunkPacketData.BlockEntityInfo>> LIST_STREAM_CODEC = STREAM_CODEC.apply(
ByteBufCodecs.list()
);
final int packedXZ;
final int y;
final BlockEntityType<?> type;
@Nullable
final CompoundTag tag;
private BlockEntityInfo(int p_195685_, int p_195686_, BlockEntityType<?> p_195687_, @Nullable CompoundTag p_195688_) {
this.packedXZ = p_195685_;
this.y = p_195686_;
this.type = p_195687_;
this.tag = p_195688_;
}
private BlockEntityInfo(RegistryFriendlyByteBuf p_335103_) {
this.packedXZ = p_335103_.readByte();
this.y = p_335103_.readShort();
this.type = ByteBufCodecs.registry(Registries.BLOCK_ENTITY_TYPE).decode(p_335103_);
this.tag = p_335103_.readNbt();
}
private void write(RegistryFriendlyByteBuf p_332659_) {
p_332659_.writeByte(this.packedXZ);
p_332659_.writeShort(this.y);
ByteBufCodecs.registry(Registries.BLOCK_ENTITY_TYPE).encode(p_332659_, this.type);
p_332659_.writeNbt(this.tag);
}
static ClientboundLevelChunkPacketData.BlockEntityInfo create(BlockEntity p_195692_) {
CompoundTag compoundtag = p_195692_.getUpdateTag(p_195692_.getLevel().registryAccess());
BlockPos blockpos = p_195692_.getBlockPos();
int i = SectionPos.sectionRelative(blockpos.getX()) << 4 | SectionPos.sectionRelative(blockpos.getZ());
return new ClientboundLevelChunkPacketData.BlockEntityInfo(
i, blockpos.getY(), p_195692_.getType(), compoundtag.isEmpty() ? null : compoundtag
);
}
}
@FunctionalInterface
public interface BlockEntityTagOutput {
void accept(BlockPos p_195696_, BlockEntityType<?> p_195697_, @Nullable CompoundTag p_195698_);
}
}