// use fastnbt::nbt; // pub const BLOCKS_AND_BIOMES: [u8; 2000] = [0x80; 2000]; // pub const SKY_LIGHT_ARRAYS: [FixedArray; 26] = [FixedArray([0xff; 2048]); 26]; // #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] // #[repr(transparent)] // pub struct FixedArray(pub [T; N]); // pub struct TestChunk { // pub heightmap: Vec, // } // impl Default for TestChunk { // fn default() -> Self { // Self::new() // } // } // impl TestChunk { // pub fn new() -> Self { // let bytes = fastnbt::to_bytes(&nbt!({"MOTION_BLOCKING": [L; 123, 256]})).unwrap(); // Self { heightmap: bytes } // } // } use std::collections::HashMap; use fastnbt::LongArray; use crate::{world::WorldError, WORLD_HEIGHT}; pub struct ChunkData { pub blocks: Box<[i64; 16 * 16 * WORLD_HEIGHT]>, pub position: (i32, i32), pub heightmaps: ChunkHeightmaps, } #[derive(serde::Deserialize, Debug, Clone)] #[serde(rename_all = "PascalCase")] struct PaletteEntry { name: String, properties: Option>, } #[derive(serde::Deserialize, Debug, Clone)] struct ChunkSectionBlockStates { data: Option, palette: Vec, } #[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] #[serde(rename_all = "UPPERCASE")] pub struct ChunkHeightmaps { motion_blocking: LongArray, world_surface: LongArray, } #[derive(serde::Deserialize, Debug)] struct ChunkSection { #[serde(rename = "Y")] y: i32, block_states: Option, } #[derive(serde::Deserialize, Debug)] struct ChunkNbt { #[serde(rename = "DataVersion")] data_version: usize, sections: Vec, #[serde(rename = "Heightmaps")] heightmaps: ChunkHeightmaps, } impl ChunkData { pub fn from_bytes(chunk_data: Vec, at: (i32, i32)) -> Result { let chunk_data = match fastnbt::from_bytes::(chunk_data.as_slice()) { Ok(v) => v, Err(err) => return Err(WorldError::ErrorDeserializingChunk(err.to_string())), }; // this needs to be boxed, otherwise it will cause a stack-overflow let mut blocks = Box::new([0; 16 * 16 * WORLD_HEIGHT]); for (k, section) in chunk_data.sections.into_iter().enumerate() { let block_states = match section.block_states { Some(states) => states, None => continue, // this should instead fill all blocks with the only element of the palette }; let palette = block_states .palette .iter() .map(|entry| { crate::block_registry::block_id_and_properties_to_block_state_id( &entry.name, entry.properties.as_ref(), ) }) .collect::, _>>()?; let block_data = match block_states.data { None => continue, Some(d) => d, } .into_inner(); let block_size = { let size = 64 - (palette.len() as i64 - 1).leading_zeros(); if size >= 4 { size } else { 4 } }; let mask = (1 << block_size) - 1; // println!("{block_size} {:#08b}", mask); // println!( // "{} {}", // block_size, // palette.iter().map(|v| v.to_string()).join(",") // ); let mut blocks_left = 16 * 16 * 16; 'block_loop: for (j, block) in block_data.iter().enumerate() { // if at == (0,0) && block_size != 4 { // println!("{} {:#066b}", 64 - (64 / block_size) * block_size, *block); // } for i in 0..64 / block_size { if blocks_left <= 0 { break 'block_loop; } let index = (block >> (i * block_size)) & mask; let block = palette[index as usize]; blocks[k * 16 * 16 * 16 + j * ((64 / block_size) as usize) + i as usize] = block; blocks_left -= 1; } } } // std::fs::File::create_new("../mafaile.txt") // .unwrap() // .write_all( // blocks // .iter() // .map(|v| v.to_string()) // .collect::>() // .join(",") // .as_bytes(), // ); // if at == (0, 0) { // println!( // "[{}]", // &blocks[0..10000].iter().map(|v| v.to_string()).join(",") // ); // } // dbg!("{}", blocks.iter().filter(|v| **v == 2005).collect_vec().len()); Ok(ChunkData { blocks, position: at, heightmaps: chunk_data.heightmaps, }) } }