ClientboundLevelChunkPacketData.java

net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData

信息

  • 全限定名:net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData
  • 类型:public class
  • 包:net.minecraft.network.protocol.game
  • 源码路径:src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
  • 起始行号:L27
  • 职责:

    TODO

字段/常量

  • HEIGHTMAPS_STREAM_CODEC

    • 类型: StreamCodec<ByteBuf,Map<Heightmap.Types,long[]>>
    • 修饰符: private static final
    • 源码定位: L28
    • 说明:

      TODO

  • TWO_MEGABYTES

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L31
    • 说明:

      TODO

  • heightmaps

    • 类型: Map<Heightmap.Types,long[]>
    • 修饰符: private final
    • 源码定位: L32
    • 说明:

      TODO

  • buffer

    • 类型: byte[]
    • 修饰符: private final
    • 源码定位: L33
    • 说明:

      TODO

  • blockEntitiesData

    • 类型: List<ClientboundLevelChunkPacketData.BlockEntityInfo>
    • 修饰符: private final
    • 源码定位: L34
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData.BlockEntityInfo

    • 类型: class
    • 修饰符: private static
    • 源码定位: L120
    • 说明:

      TODO

  • net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData.BlockEntityTagOutput

    • 类型: interface
    • 修饰符: public
    • 源码定位: L162
    • 说明:

      TODO

构造器

public ClientboundLevelChunkPacketData(LevelChunk levelChunk) @ L36

  • 构造器名:ClientboundLevelChunkPacketData
  • 源码定位:L36
  • 修饰符:public

参数:

  • levelChunk: LevelChunk

说明:

TODO

public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf input, int x, int z) @ L50

  • 构造器名:ClientboundLevelChunkPacketData
  • 源码定位:L50
  • 修饰符:public

参数:

  • input: RegistryFriendlyByteBuf
  • x: int
  • z: int

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void write(RegistryFriendlyByteBuf output) @ L62

  • 方法名:write
  • 源码定位:L62
  • 返回类型:void
  • 修饰符:public

参数:

  • output: RegistryFriendlyByteBuf

说明:

TODO

private static int calculateChunkSize(LevelChunk chunk) @ L69

  • 方法名:calculateChunkSize
  • 源码定位:L69
  • 返回类型:int
  • 修饰符:private static

参数:

  • chunk: LevelChunk

说明:

TODO

private ByteBuf getWriteBuffer() @ L79

  • 方法名:getWriteBuffer
  • 源码定位:L79
  • 返回类型:ByteBuf
  • 修饰符:private

参数:

说明:

TODO

public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) @ L85

  • 方法名:extractChunkData
  • 源码定位:L85
  • 返回类型:void
  • 修饰符:public static

参数:

  • buffer: FriendlyByteBuf
  • chunk: LevelChunk

说明:

TODO

public Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> getBlockEntitiesTagsConsumer(int x, int z) @ L95

  • 方法名:getBlockEntitiesTagsConsumer
  • 源码定位:L95
  • 返回类型:Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput>
  • 修饰符:public

参数:

  • x: int
  • z: int

说明:

TODO

private void getBlockEntitiesTags(ClientboundLevelChunkPacketData.BlockEntityTagOutput output, int x, int z) @ L99

  • 方法名:getBlockEntitiesTags
  • 源码定位:L99
  • 返回类型:void
  • 修饰符:private

参数:

  • output: ClientboundLevelChunkPacketData.BlockEntityTagOutput
  • x: int
  • z: int

说明:

TODO

public FriendlyByteBuf getReadBuffer() @ L112

  • 方法名:getReadBuffer
  • 源码定位:L112
  • 返回类型:FriendlyByteBuf
  • 修饰符:public

参数:

说明:

TODO

public Map<Heightmap.Types,long[]> getHeightmaps() @ L116

  • 方法名:getHeightmaps
  • 源码定位:L116
  • 返回类型:Map<Heightmap.Types,long[]>
  • 修饰符:public

参数:

说明:

TODO

代码

public class ClientboundLevelChunkPacketData {
    private static final StreamCodec<ByteBuf, Map<Heightmap.Types, long[]>> HEIGHTMAPS_STREAM_CODEC = ByteBufCodecs.map(
        size -> 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 levelChunk) {
        this.heightmaps = levelChunk.getHeightmaps()
            .stream()
            .filter(entryx -> ((Heightmap.Types)entryx.getKey()).sendToClient())
            .collect(Collectors.toMap(Entry::getKey, entryx -> (long[])((Heightmap)entryx.getValue()).getRawData().clone()));
        this.buffer = new byte[calculateChunkSize(levelChunk)];
        extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk);
        this.blockEntitiesData = Lists.newArrayList();
 
        for (Entry<BlockPos, BlockEntity> entry : levelChunk.getBlockEntities().entrySet()) {
            this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(entry.getValue()));
        }
    }
 
    public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf input, int x, int z) {
        this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(input);
        int size = input.readVarInt();
        if (size > 2097152) {
            throw new RuntimeException("Chunk Packet trying to allocate too much memory on read.");
        } else {
            this.buffer = new byte[size];
            input.readBytes(this.buffer);
            this.blockEntitiesData = ClientboundLevelChunkPacketData.BlockEntityInfo.LIST_STREAM_CODEC.decode(input);
        }
    }
 
    public void write(RegistryFriendlyByteBuf output) {
        HEIGHTMAPS_STREAM_CODEC.encode(output, this.heightmaps);
        output.writeVarInt(this.buffer.length);
        output.writeBytes(this.buffer);
        ClientboundLevelChunkPacketData.BlockEntityInfo.LIST_STREAM_CODEC.encode(output, this.blockEntitiesData);
    }
 
    private static int calculateChunkSize(LevelChunk chunk) {
        int total = 0;
 
        for (LevelChunkSection section : chunk.getSections()) {
            total += section.getSerializedSize();
        }
 
        return total;
    }
 
    private ByteBuf getWriteBuffer() {
        ByteBuf buffer = Unpooled.wrappedBuffer(this.buffer);
        buffer.writerIndex(0);
        return buffer;
    }
 
    public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
        for (LevelChunkSection section : chunk.getSections()) {
            section.write(buffer);
        }
 
        if (buffer.writerIndex() != buffer.capacity()) {
            throw new IllegalStateException("Didn't fill chunk buffer: expected " + buffer.capacity() + " bytes, got " + buffer.writerIndex());
        }
    }
 
    public Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> getBlockEntitiesTagsConsumer(int x, int z) {
        return output -> this.getBlockEntitiesTags(output, x, z);
    }
 
    private void getBlockEntitiesTags(ClientboundLevelChunkPacketData.BlockEntityTagOutput output, int x, int z) {
        int baseX = 16 * x;
        int baseZ = 16 * z;
        BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
 
        for (ClientboundLevelChunkPacketData.BlockEntityInfo data : this.blockEntitiesData) {
            int unpackedX = baseX + SectionPos.sectionRelative(data.packedXZ >> 4);
            int unpackedZ = baseZ + SectionPos.sectionRelative(data.packedXZ);
            pos.set(unpackedX, data.y, unpackedZ);
            output.accept(pos, data.type, data.tag);
        }
    }
 
    public FriendlyByteBuf getReadBuffer() {
        return new FriendlyByteBuf(Unpooled.wrappedBuffer(this.buffer));
    }
 
    public Map<Heightmap.Types, long[]> getHeightmaps() {
        return this.heightmaps;
    }
 
    private 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()
        );
        private final int packedXZ;
        private final int y;
        private final BlockEntityType<?> type;
        private final @Nullable CompoundTag tag;
 
        private BlockEntityInfo(int packedXZ, int y, BlockEntityType<?> type, @Nullable CompoundTag tag) {
            this.packedXZ = packedXZ;
            this.y = y;
            this.type = type;
            this.tag = tag;
        }
 
        private BlockEntityInfo(RegistryFriendlyByteBuf input) {
            this.packedXZ = input.readByte();
            this.y = input.readShort();
            this.type = ByteBufCodecs.registry(Registries.BLOCK_ENTITY_TYPE).decode(input);
            this.tag = input.readNbt();
        }
 
        private void write(RegistryFriendlyByteBuf output) {
            output.writeByte(this.packedXZ);
            output.writeShort(this.y);
            ByteBufCodecs.registry(Registries.BLOCK_ENTITY_TYPE).encode(output, this.type);
            output.writeNbt(this.tag);
        }
 
        private static ClientboundLevelChunkPacketData.BlockEntityInfo create(BlockEntity blockEntity) {
            CompoundTag tag = blockEntity.getUpdateTag(blockEntity.getLevel().registryAccess());
            BlockPos pos = blockEntity.getBlockPos();
            int xz = SectionPos.sectionRelative(pos.getX()) << 4 | SectionPos.sectionRelative(pos.getZ());
            return new ClientboundLevelChunkPacketData.BlockEntityInfo(xz, pos.getY(), blockEntity.getType(), tag.isEmpty() ? null : tag);
        }
    }
 
    @FunctionalInterface
    public interface BlockEntityTagOutput {
        void accept(BlockPos pos, BlockEntityType<?> type, @Nullable CompoundTag tag);
    }
}

引用的其他类

  • BlockPos

    • 引用位置: 方法调用/构造调用
    • 关联成员: BlockPos.MutableBlockPos(), MutableBlockPos()
  • SectionPos

    • 引用位置: 方法调用
    • 关联成员: SectionPos.sectionRelative()
  • FriendlyByteBuf

    • 引用位置: 参数/构造调用/返回值
    • 关联成员: FriendlyByteBuf()
  • RegistryFriendlyByteBuf

    • 引用位置: 参数
  • ByteBufCodecs

    • 引用位置: 方法调用
    • 关联成员: ByteBufCodecs.list(), ByteBufCodecs.map(), ByteBufCodecs.registry()
  • StreamCodec

    • 引用位置: 字段/方法调用
    • 关联成员: StreamCodec.ofMember()
  • LevelChunk

    • 引用位置: 参数
  • Heightmap

    • 引用位置: 字段/返回值