Read and Write light data using Anvil
Now we are reading and writing light data to and from the anvil format and send it in the chunk and light packet
This commit is contained in:
parent
f0636bb924
commit
fbd95cb693
@ -60,4 +60,4 @@ serde_json = "1.0"
|
||||
|
||||
async-trait = "0.1"
|
||||
|
||||
tempfile = "3.17.1"
|
||||
tempfile = "3.19.1"
|
||||
|
||||
@ -29,11 +29,11 @@ aes = "0.8"
|
||||
cfb8 = "0.8"
|
||||
|
||||
# compression
|
||||
async-compression = { version = "0.4.20", features = ["tokio", "zlib"] }
|
||||
async-compression = { version = "0.4.22", features = ["tokio", "zlib"] }
|
||||
|
||||
take_mut = "0.2.2"
|
||||
bitflags = "2.9.0"
|
||||
|
||||
[dev-dependencies]
|
||||
# Validate correctness
|
||||
flate2 = "1.1.0"
|
||||
flate2 = "1.1.1"
|
||||
|
||||
@ -8,10 +8,7 @@ use crate::{
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_LEVEL_CHUNK_WITH_LIGHT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_world::chunk::{
|
||||
ChunkData,
|
||||
palette::{BlockPalette, NetworkPalette},
|
||||
};
|
||||
use pumpkin_world::chunk::{ChunkData, palette::NetworkPalette};
|
||||
|
||||
#[packet(PLAY_LEVEL_CHUNK_WITH_LIGHT)]
|
||||
pub struct CChunkData<'a>(pub &'a ChunkData);
|
||||
@ -45,21 +42,40 @@ impl ClientPacket for CChunkData<'_> {
|
||||
}
|
||||
|
||||
let mut data_buf = Vec::new();
|
||||
let mut light_buf = Vec::new();
|
||||
|
||||
for section in self.0.section.sections.iter() {
|
||||
// 2 blocks per byte for block lights
|
||||
let chunk_light_len = BlockPalette::VOLUME / 2;
|
||||
// TODO: Implement, currently default to full bright
|
||||
let chunk_light = vec![0xFFu8; chunk_light_len];
|
||||
let mut sky_light_buf = Vec::new();
|
||||
let mut sky_light_empty_mask = 0;
|
||||
let mut sky_light_mask = 0;
|
||||
let mut block_light_buf = Vec::new();
|
||||
let mut block_light_empty_mask = 0;
|
||||
let mut block_light_mask = 0;
|
||||
|
||||
light_buf.write_var_int(&chunk_light_len.try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
chunk_light_len
|
||||
))
|
||||
for (i, section) in self.0.section.sections.iter().enumerate() {
|
||||
// Write sky light
|
||||
if let Some(sky_light) = §ion.sky_light {
|
||||
let mut buf = Vec::new();
|
||||
buf.write_var_int(&sky_light.len().try_into().map_err(|_| {
|
||||
WritingError::Message("sky_light not representable as a VarInt!".to_string())
|
||||
})?)?;
|
||||
light_buf.write_slice(&chunk_light)?;
|
||||
buf.write_slice(sky_light)?;
|
||||
sky_light_buf.push(buf);
|
||||
sky_light_mask |= 1 << i;
|
||||
} else {
|
||||
sky_light_empty_mask |= 1 << i;
|
||||
}
|
||||
|
||||
// Write block light
|
||||
if let Some(block_light) = §ion.block_light {
|
||||
let mut buf = Vec::new();
|
||||
buf.write_var_int(&block_light.len().try_into().map_err(|_| {
|
||||
WritingError::Message("block_light not representable as a VarInt!".to_string())
|
||||
})?)?;
|
||||
buf.write_slice(block_light)?;
|
||||
block_light_buf.push(buf);
|
||||
block_light_mask |= 1 << i;
|
||||
} else {
|
||||
block_light_empty_mask |= 1 << i;
|
||||
}
|
||||
|
||||
// Block count
|
||||
let non_empty_block_count = section.block_states.non_air_block_count() as i16;
|
||||
@ -131,27 +147,29 @@ impl ClientPacket for CChunkData<'_> {
|
||||
// TODO: block entities
|
||||
write.write_var_int(&VarInt(0))?;
|
||||
|
||||
// Sky Light Mask
|
||||
// All of the chunks, this is not optimal and uses way more data than needed but will be
|
||||
// overhauled with a full lighting system.
|
||||
write.write_bitset(&BitSet(Box::new([0b01111111111111111111111110])))?;
|
||||
|
||||
// Sky Light Mask
|
||||
write.write_bitset(&BitSet(Box::new([sky_light_mask])))?;
|
||||
// Block Light Mask
|
||||
write.write_bitset(&BitSet(Box::new([0])))?;
|
||||
write.write_bitset(&BitSet(Box::new([block_light_mask])))?;
|
||||
// Empty Sky Light Mask
|
||||
write.write_bitset(&BitSet(Box::new([0])))?;
|
||||
write.write_bitset(&BitSet(Box::new([sky_light_empty_mask])))?;
|
||||
// Empty Block Light Mask
|
||||
write.write_bitset(&BitSet(Box::new([0])))?;
|
||||
write.write_bitset(&BitSet(Box::new([block_light_empty_mask])))?;
|
||||
|
||||
// Sky light
|
||||
write.write_var_int(&self.0.section.sections.len().try_into().map_err(|_| {
|
||||
WritingError::Message(format!(
|
||||
"{} is not representable as a VarInt!",
|
||||
self.0.section.sections.len()
|
||||
))
|
||||
})?)?;
|
||||
write.write_slice(&light_buf)?;
|
||||
write.write_var_int(&VarInt(sky_light_buf.len() as i32))?;
|
||||
for sky_buf in sky_light_buf {
|
||||
write.write_slice(&sky_buf)?;
|
||||
}
|
||||
|
||||
// Block Lighting
|
||||
write.write_var_int(&VarInt(0))
|
||||
// Block Light
|
||||
write.write_var_int(&VarInt(block_light_buf.len() as i32))?;
|
||||
for block_buf in block_light_buf {
|
||||
write.write_slice(&block_buf)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ pumpkin-protocol = { path = "../pumpkin-protocol" }
|
||||
pumpkin-nbt = { path = "../pumpkin-nbt" }
|
||||
pumpkin-util = { path = "../pumpkin-util" }
|
||||
|
||||
indexmap = { version = "2.8", features = ["serde"] }
|
||||
indexmap = { version = "2.9", features = ["serde"] }
|
||||
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@ -40,7 +40,7 @@ zstd = "0.13.3"
|
||||
|
||||
itertools = "0.14.0"
|
||||
file-guard = "0.2"
|
||||
indexmap = "2.8"
|
||||
indexmap = "2.9"
|
||||
enum_dispatch = "0.3"
|
||||
noise = "0.9"
|
||||
derive-getters = "0.5.0"
|
||||
@ -54,7 +54,7 @@ tokio-util = { version = "0.7.14", features = ["rt"] }
|
||||
criterion = { version = "0.5", features = ["html_reports", "async_tokio"] }
|
||||
temp-dir = "0.1.14"
|
||||
# Print log info inside tests when needed
|
||||
env_logger = "0.11.7"
|
||||
env_logger = "0.11.8"
|
||||
# Allows us to modify the config
|
||||
pumpkin-config = { path = "../pumpkin-config", features = ["test_helper"] }
|
||||
# Deserialize NaN and Inf
|
||||
|
||||
@ -827,6 +827,8 @@ pub fn chunk_to_bytes(chunk_data: &ChunkData) -> Result<Vec<u8>, ChunkSerializin
|
||||
y: i as i8 + section_coords::block_to_section(chunk_data.section.min_y) as i8,
|
||||
block_states,
|
||||
biomes,
|
||||
block_light: section.block_light.clone(), // :c
|
||||
sky_light: section.sky_light.clone(), // :c
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -54,6 +54,8 @@ impl ChunkData {
|
||||
.map(|section| SubChunk {
|
||||
block_states: BlockPalette::from_disk_nbt(section.block_states),
|
||||
biomes: BiomePalette::from_disk_nbt(section.biomes),
|
||||
block_light: section.block_light,
|
||||
sky_light: section.sky_light,
|
||||
})
|
||||
.collect();
|
||||
let min_y = section_coords::section_to_block(chunk_data.min_y_section);
|
||||
@ -101,11 +103,10 @@ impl ChunkData {
|
||||
struct ChunkSectionNBT {
|
||||
block_states: ChunkSectionBlockStates,
|
||||
biomes: ChunkSectionBiomes,
|
||||
// TODO
|
||||
// #[serde(rename = "BlockLight", skip_serializing_if = "Option::is_none")]
|
||||
// block_light: Option<Box<[u8]>>,
|
||||
// #[serde(rename = "SkyLight", skip_serializing_if = "Option::is_none")]
|
||||
// sky_light: Option<Box<[u8]>>,
|
||||
#[serde(rename = "BlockLight", skip_serializing_if = "Option::is_none")]
|
||||
block_light: Option<Box<[u8]>>,
|
||||
#[serde(rename = "SkyLight", skip_serializing_if = "Option::is_none")]
|
||||
sky_light: Option<Box<[u8]>>,
|
||||
#[serde(rename = "Y")]
|
||||
y: i8,
|
||||
}
|
||||
|
||||
@ -129,6 +129,7 @@ pub struct ChunkSections {
|
||||
impl ChunkSections {
|
||||
#[cfg(test)]
|
||||
pub fn dump_blocks(&self) -> Vec<u16> {
|
||||
// TODO: this is not optimal, we could use rust iters
|
||||
let mut dump = Vec::new();
|
||||
for section in self.sections.iter() {
|
||||
section.block_states.for_each(|raw_id| {
|
||||
@ -140,6 +141,7 @@ impl ChunkSections {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn dump_biomes(&self) -> Vec<u8> {
|
||||
// TODO: this is not optimal, we could use rust iters
|
||||
let mut dump = Vec::new();
|
||||
for section in self.sections.iter() {
|
||||
section.biomes.for_each(|raw_id| {
|
||||
@ -154,6 +156,19 @@ impl ChunkSections {
|
||||
pub struct SubChunk {
|
||||
pub block_states: BlockPalette,
|
||||
pub biomes: BiomePalette,
|
||||
pub block_light: Option<Box<[u8]>>,
|
||||
pub sky_light: Option<Box<[u8]>>,
|
||||
}
|
||||
|
||||
impl SubChunk {
|
||||
pub fn max_light() -> Self {
|
||||
let chunk_light_len = BlockPalette::VOLUME / 2;
|
||||
Self {
|
||||
block_light: Some(vec![0xFFu8; chunk_light_len].into_boxed_slice()),
|
||||
sky_light: Some(vec![0xFFu8; chunk_light_len].into_boxed_slice()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
|
||||
@ -43,7 +43,7 @@ impl WorldGenerator for VanillaGenerator {
|
||||
.unwrap();
|
||||
|
||||
let sub_chunks = generation_settings.shape.height as usize / BlockPalette::SIZE;
|
||||
let sections = (0..sub_chunks).map(|_| SubChunk::default()).collect();
|
||||
let sections = (0..sub_chunks).map(|_| SubChunk::max_light()).collect();
|
||||
let mut sections = ChunkSections::new(sections, generation_settings.shape.min_y as i32);
|
||||
|
||||
let mut proto_chunk = ProtoChunk::new(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user