Skip to content

Commit

Permalink
Load sky and block light from world save and send it to clients - res…
Browse files Browse the repository at this point in the history
…olves #103 (#117)
  • Loading branch information
NyxCode authored and caelunshun committed Sep 7, 2019
1 parent 6ba0de6 commit b9218d6
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 27 deletions.
14 changes: 10 additions & 4 deletions core/src/network/packet/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,7 @@ impl Packet for ChunkData {

buf.write_var_int(primary_mask as i32);

// TODO: approximate appropriate capacity
let mut temp_buf = ByteBuf::new();

for section in self.chunk.sections() {
Expand All @@ -1330,10 +1331,15 @@ impl Packet for ChunkData {
temp_buf.write_u64_be(*val);
}

// Light — TODO
for _ in 0..4096 {
temp_buf.write_u8(0b1111_1111);
}
// Light
let sky_light_data = section.sky_light();
let block_light_data = section.block_light();

block_light_data
.inner()
.iter()
.chain(sky_light_data.inner().iter())
.for_each(|data| temp_buf.write_u64_le(*data));
}
}

Expand Down
49 changes: 43 additions & 6 deletions core/src/save/region.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
//! This module implements the loading and saving (soon)
//! of Anvil region files.

use crate::world::block::*;
use crate::world::chunk::{BitArray, Chunk, ChunkSection};
use crate::world::ChunkPosition;
use byteorder::{BigEndian, ReadBytesExt};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};
use std::fs::File;
Expand All @@ -14,6 +9,13 @@ use std::io::prelude::*;
use std::io::{Cursor, SeekFrom};
use std::path::PathBuf;

use byteorder::{BigEndian, ReadBytesExt};
use serde::Deserialize;

use crate::world::block::*;
use crate::world::chunk::{BitArray, Chunk, ChunkSection};
use crate::world::ChunkPosition;

/// The length and width of a region, in chunks.
const REGION_SIZE: usize = 32;

Expand Down Expand Up @@ -51,6 +53,10 @@ struct LevelSection {
states: Vec<i64>,
#[serde(rename = "Palette")]
palette: Vec<LevelPaletteEntry>,
#[serde(rename = "BlockLight")]
block_light: Vec<i8>,
#[serde(rename = "SkyLight")]
sky_light: Vec<i8>,
}

/// Represents a palette entry in a region file.
Expand Down Expand Up @@ -189,7 +195,38 @@ fn read_section_into_chunk(section: &LevelSection, chunk: &mut Chunk) -> Result<
((data.len() as f32 * 64.0) / 4096.0).ceil() as u8,
4096,
);
let chunk_section = ChunkSection::from_data_and_palette(data, Some(palette));

// Light
// convert raw lighting data (4bits / block) into a BitArray
let convert_light_data = |light_data: &Vec<i8>| {
let data = light_data
.chunks(8)
.map(|chunk| {
// not sure if there's a better (safe) way of doing this..
let chunk: [u8; 8] = [
chunk[0] as u8,
chunk[1] as u8,
chunk[2] as u8,
chunk[3] as u8,
chunk[4] as u8,
chunk[5] as u8,
chunk[6] as u8,
chunk[7] as u8,
];
u64::from_le_bytes(chunk)
})
.collect();
BitArray::from_raw(data, 4, 4096)
};

if section.block_light.len() != 2048 || section.sky_light.len() != 2048 {
return Err(Error::IndexOutOfBounds);
}

let block_light = convert_light_data(&section.block_light);
let sky_light = convert_light_data(&section.sky_light);

let chunk_section = ChunkSection::new(data, Some(palette), block_light, sky_light);

if section.y >= 16 {
// Haha... nope.
Expand Down
53 changes: 36 additions & 17 deletions core/src/world/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl Chunk {
return; // Nothing to do - section already empty
}

let new_section = ChunkSection::new();
let new_section = ChunkSection::default();
self.set_section_at(y / 16, Some(new_section));
section = self.section_mut(y / 16).unwrap();
}
Expand Down Expand Up @@ -217,26 +217,22 @@ pub struct ChunkSection {
/// the section becomes empty.
solid_block_count: u16,

block_light: BitArray,
sky_light: BitArray,

/// A section is considered dirty when it has been
/// modified since the last time it was optimized.
dirty: bool,
}

impl ChunkSection {
/// Creates a new, empty `ChunkSection`.
pub fn new() -> Self {
let air_id = Block::Air.native_state_id();
Self {
data: BitArray::new(4, SECTION_VOLUME),
palette: Some(vec![air_id]),
solid_block_count: 0,
dirty: false,
}
}

/// Creates a new `ChunkSection` based on the given
/// data and palette.
pub fn from_data_and_palette(mut data: BitArray, mut palette: Option<Vec<u16>>) -> Self {
pub fn new(
mut data: BitArray,
mut palette: Option<Vec<u16>>,
block_light: BitArray,
sky_light: BitArray,
) -> Self {
// Correct palette if not using the global palette
if let Some(palette) = palette.as_mut() {
Self::correct_data_and_palette(&mut data, palette);
Expand All @@ -259,6 +255,8 @@ impl ChunkSection {
palette,
solid_block_count,
dirty: false,
block_light,
sky_light,
}
}

Expand Down Expand Up @@ -466,11 +464,27 @@ impl ChunkSection {
pub fn bits_per_block(&self) -> u8 {
self.data.bits_per_value
}

pub fn sky_light(&self) -> &BitArray {
&self.sky_light
}

pub fn block_light(&self) -> &BitArray {
&self.block_light
}
}

impl Default for ChunkSection {
fn default() -> Self {
Self::new()
let air_id = Block::Air.native_state_id();
Self {
data: BitArray::new(4, SECTION_VOLUME),
palette: Some(vec![air_id]),
solid_block_count: 0,
dirty: false,
block_light: BitArray::new(4, SECTION_VOLUME),
sky_light: BitArray::new(4, SECTION_VOLUME),
}
}
}

Expand Down Expand Up @@ -782,7 +796,12 @@ mod tests {
}

let palette = vec![1];
let section = ChunkSection::from_data_and_palette(data, Some(palette));
let section = ChunkSection::new(
data,
Some(palette),
BitArray::new(4, SECTION_VOLUME),
BitArray::new(4, SECTION_VOLUME),
);
chunk.set_section_at(0, Some(section));

for x in 0..16 {
Expand Down Expand Up @@ -907,7 +926,7 @@ mod tests {

#[test]
fn test_palette_insertion_in_middle() {
let mut chunk = ChunkSection::new();
let mut chunk = ChunkSection::default();

chunk.set_block_at(0, 0, 0, Block::Cobblestone);
chunk.set_block_at(0, 1, 0, Block::Stone);
Expand Down

0 comments on commit b9218d6

Please sign in to comment.