mclib 0.0.1

Utils and helpers for Minecraft protocol
Documentation
use std::io::Read;

use mclib_macros::{MCPacket, MCType};

use crate::chunk_format::ChunkData;
use crate::packets::base::MCPacket;
use crate::types::base::MCType;
use crate::types::bitset::MCBitSet;
use crate::types::byte::MCByte;
use crate::types::byte_array::MCByteArray;
use crate::types::int::MCInt;
use crate::types::nbt::MCNBT;
use crate::types::short::MCShort;
use crate::types::varint::MCVarInt;

#[derive(MCType, Debug, Clone)]
pub struct BlockEntity {
    pub packed_xy: MCByte,
    pub y: MCShort,
    pub ty: MCVarInt,
    pub data: MCNBT,
}

#[derive(MCPacket, Debug, Clone)]
#[packet(packet_id = 0x25)]
pub struct ChunkDataAndUpdateLight {
    pub chunk_x: MCInt,
    pub chunk_z: MCInt,
    pub heightmaps: MCNBT,
    pub data: MCByteArray<ChunkData>,
    pub block_entities: Vec<BlockEntity>,
    pub sky_light_mask: MCBitSet,
    pub block_light_mask: MCBitSet,
    pub empty_sky_light_mask: MCBitSet,
    pub empty_block_light_mask: MCBitSet,
    pub sky_lights: Vec<Vec<MCByte>>,
    pub block_lights: Vec<Vec<MCByte>>,
}

#[cfg(test)]
mod tests {
    use crate::chunk_format::data_array::DataArray;
    use crate::chunk_format::palleted_container::PalletedContainer;
    use crate::chunk_format::section::ChunkSection;
    use crate::chunk_format::ChunkData;
    use crate::nbt::IntoNBTTag;
    use crate::nbt::NBT;
    use crate::packets::base::MCPacket;
    use crate::packets::client::chunk_data_and_update_light::ChunkDataAndUpdateLight;
    use crate::types::bitset::MCBitSet;
    use crate::types::byte_array::MCByteArray;
    use crate::types::long::MCLong;

    #[test]
    fn test_chunk_data() {
        let reference =
            include_bytes!("../../../tests/references/chunk_data_and_update_light.packet");

        let heightmap = NBT(
            None,
            vec![
                (
                    "MOTION_BLOCKING",
                    DataArray::from(vec![4; 256]).pack(9).to_nbt(),
                ),
                (
                    "WORLD_SURFACE",
                    DataArray::from(vec![4; 256]).pack(9).to_nbt(),
                ),
            ]
            .to_nbt(),
        );

        let mut data = Vec::new();
        data.extend(vec![1; 256]);
        data.extend(vec![2; 512]);
        data.extend(vec![3; 256]);
        data.extend(vec![0; 3072]);
        let mut chunks = Vec::new();
        chunks.push(ChunkSection {
            block_count: 1024.into(),
            block_states: PalletedContainer::Indirect {
                bits_per_entry: 4.into(),
                pallete: vec![0.into(), 79.into(), 10.into(), 9.into()],
                data: DataArray::from(data)
                    .pack(4)
                    .iter()
                    .map(|i| i.clone().into())
                    .collect::<Vec<MCLong>>(),
            },
            biomes: PalletedContainer::SingleValued(39.into()),
        });
        chunks.extend(vec![
            ChunkSection {
                block_count: 0.into(),
                block_states: PalletedContainer::SingleValued(0.into()),
                biomes: PalletedContainer::SingleValued(39.into()),
            };
            23
        ]);
        let mut sky_light_mask = MCBitSet::default();
        sky_light_mask.push(false);
        sky_light_mask.push(true);
        sky_light_mask.push(true);
        let block_light_mask = MCBitSet::default();
        let mut empty_sky_light_mask = MCBitSet::default();
        empty_sky_light_mask.push(true);
        let mut empty_block_light_mask = MCBitSet::default();
        empty_block_light_mask.push(true);
        empty_block_light_mask.push(true);
        empty_block_light_mask.push(true);

        let mut sky = vec![0.into(); 512];
        sky.extend(vec![(0x0F | (0x0F << 4)).into(); 1536]);
        let sky_lights = vec![sky, vec![(0x0F | (0x0F << 4)).into(); 2048]];

        let block_lights = vec![];

        let chunk_data_and_update_light = ChunkDataAndUpdateLight {
            chunk_x: (-1 as i32).into(),
            chunk_z: 0.into(),
            heightmaps: heightmap.into(),
            data: MCByteArray::new(ChunkData(chunks)),
            block_entities: vec![],
            sky_light_mask,
            block_light_mask,
            empty_sky_light_mask,
            empty_block_light_mask,
            sky_lights,
            block_lights,
        };

        let packed = &chunk_data_and_update_light.pack()[2..];
        assert_eq!(packed, reference);
    }
}