All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.hollowcube.polar.PolarWriter Maven / Gradle / Ivy

The newest version!
package net.hollowcube.polar;

import com.github.luben.zstd.Zstd;
import net.minestom.server.instance.Chunk;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.chunk.ChunkUtils;
import org.jetbrains.annotations.NotNull;

import java.nio.ByteBuffer;

import static net.minestom.server.network.NetworkBuffer.*;

@SuppressWarnings("UnstableApiUsage")
public class PolarWriter {
    private PolarWriter() {
    }

    public static byte[] write(@NotNull PolarWorld world) {
        return write(world, PolarDataConverter.NOOP);
    }

    public static byte[] write(@NotNull PolarWorld world, @NotNull PolarDataConverter dataConverter) {
        // Write the compressed content first
        var content = new NetworkBuffer(ByteBuffer.allocate(1024));
        content.write(BYTE, world.minSection());
        content.write(BYTE, world.maxSection());
        content.write(BYTE_ARRAY, world.userData());
        content.writeCollection(world.chunks(), (b, c) -> writeChunk(b, c, world.maxSection() - world.minSection() + 1));

        // Create final buffer
        return NetworkBuffer.makeArray(buffer -> {
            buffer.write(INT, PolarWorld.MAGIC_NUMBER);
            buffer.write(SHORT, PolarWorld.VERSION_IMPROVED_LIGHT);
            buffer.write(VAR_INT, dataConverter.dataVersion());
            buffer.write(BYTE, (byte) world.compression().ordinal());
            switch (world.compression()) {
                case NONE -> {
                    buffer.write(VAR_INT, content.readableBytes());
                    buffer.write(RAW_BYTES, content.readBytes(content.readableBytes()));
                }
                case ZSTD -> {
                    buffer.write(VAR_INT, content.readableBytes());
                    buffer.write(RAW_BYTES, Zstd.compress(content.readBytes(content.readableBytes())));
                }
            }
        });
    }

    private static void writeChunk(@NotNull NetworkBuffer buffer, @NotNull PolarChunk chunk, int sectionCount) {
        buffer.write(VAR_INT, chunk.x());
        buffer.write(VAR_INT, chunk.z());

        assert sectionCount == chunk.sections().length : "section count and chunk section length mismatch";

        for (var section : chunk.sections()) {
            writeSection(buffer, section);
        }
        buffer.writeCollection(chunk.blockEntities(), PolarWriter::writeBlockEntity);

        {
            int heightmapBits = 0;
            for (int i = 0; i < PolarChunk.MAX_HEIGHTMAPS; i++) {
                if (chunk.heightmap(i) != null)
                    heightmapBits |= 1 << i;
            }
            buffer.write(INT, heightmapBits);

            int bitsPerEntry = PaletteUtil.bitsToRepresent(sectionCount * Chunk.CHUNK_SECTION_SIZE);
            for (int i = 0; i < PolarChunk.MAX_HEIGHTMAPS; i++) {
                var heightmap = chunk.heightmap(i);
                if (heightmap == null) continue;
                if (heightmap.length == 0) buffer.write(LONG_ARRAY, new long[0]);
                else buffer.write(LONG_ARRAY, PaletteUtil.pack(heightmap, bitsPerEntry));
            }
        }

        buffer.write(BYTE_ARRAY, chunk.userData());
    }

    private static void writeSection(@NotNull NetworkBuffer buffer, @NotNull PolarSection section) {
        buffer.write(BOOLEAN, section.isEmpty());
        if (section.isEmpty()) return;

        // Blocks
        var blockPalette = section.blockPalette();
        buffer.writeCollection(STRING, blockPalette);
        if (blockPalette.length > 1) {
            var blockData = section.blockData();
            var bitsPerEntry = (int) Math.ceil(Math.log(blockPalette.length) / Math.log(2));
            if (bitsPerEntry < 1) bitsPerEntry = 1;
            buffer.write(LONG_ARRAY, PaletteUtil.pack(blockData, bitsPerEntry));
        }

        // Biomes
        var biomePalette = section.biomePalette();
        buffer.writeCollection(STRING, biomePalette);
        if (biomePalette.length > 1) {
            var biomeData = section.biomeData();
            var bitsPerEntry = (int) Math.ceil(Math.log(biomePalette.length) / Math.log(2));
            if (bitsPerEntry < 1) bitsPerEntry = 1;
            buffer.write(LONG_ARRAY, PaletteUtil.pack(biomeData, bitsPerEntry));
        }

        // Light
        buffer.write(BYTE, (byte) section.blockLightContent().ordinal());
        if (section.blockLightContent() == PolarSection.LightContent.PRESENT)
            buffer.write(RAW_BYTES, section.blockLight());
        buffer.write(BYTE, (byte) section.skyLightContent().ordinal());
        if (section.skyLightContent() == PolarSection.LightContent.PRESENT)
            buffer.write(RAW_BYTES, section.skyLight());
    }

    private static void writeBlockEntity(@NotNull NetworkBuffer buffer, @NotNull PolarChunk.BlockEntity blockEntity) {
        var index = ChunkUtils.getBlockIndex(blockEntity.x(), blockEntity.y(), blockEntity.z());
        buffer.write(INT, index);
        buffer.writeOptional(STRING, blockEntity.id());
        buffer.writeOptional(NBT, blockEntity.data());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy