diff --git a/src/world/mod.rs b/src/world/mod.rs index 908187a..4330869 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -1039,6 +1039,10 @@ impl World { let chunk = self.chunks.get_mut(&cpos).unwrap(); for i1 in 0..num_sections as i32 { + if mask & (1 << i1) == 0 { + continue; + } + let i: i32 = (i1 as i32) + (self.min_y >> 4); if self.protocol_version >= 451 { @@ -1412,6 +1416,7 @@ impl Section { /// The kind of palette we are reading. This can affect how we interpret bits /// per entry which is different between block states and biomes. +#[derive(PartialEq)] enum PaletteKind { BlockStates, Biomes, @@ -1435,6 +1440,10 @@ struct PaletteParser<'a> { impl PaletteParser<'_> { pub fn new(protocol_version: i32, kind: PaletteKind, data: &mut Cursor>) -> PaletteParser<'_> { + if protocol_version < 757 && kind == PaletteKind::Biomes { + panic!("Protocol {} doesn't support biome palettes", protocol_version); + } + PaletteParser { protocol_version, kind, @@ -1460,8 +1469,12 @@ impl PaletteParser<'_> { pub fn parse(mut self) -> Result { let mut bits_per_entry = self.data.read_u8()?; + // Pre 1.18, when bits_per_entry == 0, it indicates we should use + // an indirect palette rather than the new single valued one. We are + // setting this to 4 since it's the minimum value for indirect + // palettes. if self.protocol_version < 757 && bits_per_entry == 0 { - bits_per_entry = 13; + bits_per_entry = 4; } // Figure out how we should interpret the palette based on bits_per_entry. @@ -1471,13 +1484,13 @@ impl PaletteParser<'_> { n if (1..9).contains(&n) => self.parse_indirect_palette(n.max(4))?, n if (9..17).contains(&n) => PaletteFormat::Direct(n), // https://wiki.vg/Chunk_Format#Data_structure "This increase can go up to 16 bits per block"... - n => panic!("PaletteParser::parse: block state bits_per_entry={:?} > 16", n), + n => panic!("PaletteParser::parse: block state bits_per_entry={} > 16", n), }, PaletteKind::Biomes => match bits_per_entry { 0 => self.parse_single_valued_palette()?, n if (1..4).contains(&n) => self.parse_indirect_palette(n)?, n if (4..17).contains(&n) => PaletteFormat::Direct(n), - n => panic!("PaletteParser::parse: biome bits_per_entry={:?} > 16", n), + n => panic!("PaletteParser::parse: biome bits_per_entry={} > 16", n), }, }) } @@ -1517,7 +1530,7 @@ impl SectionParser<'_> { section.dirty = true; let bits = LenPrefixed::::read_from(self.data)?.data; - let padded = self.protocol_version >= 736; + let padded = self.protocol_version >= 735; match self.palette { PaletteFormat::SingleValued(id) => { @@ -1547,4 +1560,143 @@ impl SectionParser<'_> { Ok(section) } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_chunk_1_12_2() { + let mut world = World::new(340); + let chunk_data = std::fs::read("test/chunk_1.12.2.bin").unwrap(); + world.load_chunk19_to_117(true, 7, 8, true, 63, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_13_2() { + let mut world = World::new(404); + let chunk_data = std::fs::read("test/chunk_1.13.2.bin").unwrap(); + world.load_chunk19_to_117(true, -20, -7, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_18w50a() { + let mut world = World::new(451); + let chunk_data = std::fs::read("test/chunk_18w50a.bin").unwrap(); + world.load_chunk19_to_117(true, -25, -18, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_19w02a() { + let mut world = World::new(452); + let chunk_data = std::fs::read("test/chunk_19w02a.bin").unwrap(); + world.load_chunk19_to_117(true, -10, -26, true, 15, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_14() { + let mut world = World::new(477); + let chunk_data = std::fs::read("test/chunk_1.14.bin").unwrap(); + world.load_chunk19_to_117(true, -14, 0, true, 63, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_14_1() { + let mut world = World::new(480); + let chunk_data = std::fs::read("test/chunk_1.14.1.bin").unwrap(); + world.load_chunk19_to_117(true, 2, -25, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_14_2() { + let mut world = World::new(485); + let chunk_data = std::fs::read("test/chunk_1.14.2.bin").unwrap(); + world.load_chunk19_to_117(true, 1, 5, true, 15, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_14_3() { + let mut world = World::new(490); + let chunk_data = std::fs::read("test/chunk_1.14.3.bin").unwrap(); + world.load_chunk19_to_117(true, -9, -25, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_14_4() { + let mut world = World::new(498); + let chunk_data = std::fs::read("test/chunk_1.14.4.bin").unwrap(); + world.load_chunk19_to_117(true, 2, -14, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_15_1() { + let mut world = World::new(575); + let chunk_data = std::fs::read("test/chunk_1.15.1.bin").unwrap(); + world.load_chunk19_to_117(false, -10, -10, true, 63, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_15_2() { + let mut world = World::new(578); + let chunk_data = std::fs::read("test/chunk_1.15.2.bin").unwrap(); + world.load_chunk19_to_117(false, -19, -18, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_16() { + let mut world = World::new(735); + let chunk_data = std::fs::read("test/chunk_1.16.bin").unwrap(); + world.load_chunk19_to_117(false, 2, -26, true, 63, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_16_1() { + let mut world = World::new(736); + let chunk_data = std::fs::read("test/chunk_1.16.1.bin").unwrap(); + world.load_chunk19_to_117(false, -6, -5, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_16_2() { + let mut world = World::new(751); + let chunk_data = std::fs::read("test/chunk_1.16.2.bin").unwrap(); + world.load_chunk19_to_117(false, -22, -20, true, 15, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_16_3() { + let mut world = World::new(753); + let chunk_data = std::fs::read("test/chunk_1.16.3.bin").unwrap(); + world.load_chunk19_to_117(false, 4, 2, true, 63, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_16_4() { + let mut world = World::new(754); + let chunk_data = std::fs::read("test/chunk_1.16.4.bin").unwrap(); + world.load_chunk19_to_117(false, -10, -8, true, 15, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_17_1() { + let mut world = World::new(756); + let chunk_data = std::fs::read("test/chunk_1.17.1.bin").unwrap(); + world.load_chunk19_to_117(false, -3, -25, true, 31, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_18_1() { + let mut world = World::new(757); + let chunk_data = std::fs::read("test/chunk_1.18.1.bin").unwrap(); + world.load_chunk19_to_117(false, -14, -5, true, 65535, 16, chunk_data).unwrap(); + } + + #[test] + fn parse_chunk_1_18_2() { + let mut world = World::new(758); + let chunk_data = std::fs::read("test/chunk_1.18.2.bin").unwrap(); + world.load_chunk19_to_117(false, -10, -8, true, 65535, 16, chunk_data).unwrap(); + } } \ No newline at end of file diff --git a/test/chunk_1.12.2.bin b/test/chunk_1.12.2.bin new file mode 100644 index 0000000..8f5fe3a Binary files /dev/null and b/test/chunk_1.12.2.bin differ diff --git a/test/chunk_1.13.2.bin b/test/chunk_1.13.2.bin new file mode 100644 index 0000000..bf97d85 Binary files /dev/null and b/test/chunk_1.13.2.bin differ diff --git a/test/chunk_1.14.1.bin b/test/chunk_1.14.1.bin new file mode 100644 index 0000000..1f24a5f Binary files /dev/null and b/test/chunk_1.14.1.bin differ diff --git a/test/chunk_1.14.2.bin b/test/chunk_1.14.2.bin new file mode 100644 index 0000000..ec4baa7 Binary files /dev/null and b/test/chunk_1.14.2.bin differ diff --git a/test/chunk_1.14.3.bin b/test/chunk_1.14.3.bin new file mode 100644 index 0000000..c5caf6f Binary files /dev/null and b/test/chunk_1.14.3.bin differ diff --git a/test/chunk_1.14.4.bin b/test/chunk_1.14.4.bin new file mode 100644 index 0000000..8fdbc8a Binary files /dev/null and b/test/chunk_1.14.4.bin differ diff --git a/test/chunk_1.14.bin b/test/chunk_1.14.bin new file mode 100644 index 0000000..d7127a3 Binary files /dev/null and b/test/chunk_1.14.bin differ diff --git a/test/chunk_1.15.1.bin b/test/chunk_1.15.1.bin new file mode 100644 index 0000000..c4c0e85 Binary files /dev/null and b/test/chunk_1.15.1.bin differ diff --git a/test/chunk_1.15.2.bin b/test/chunk_1.15.2.bin new file mode 100644 index 0000000..cd6e66c Binary files /dev/null and b/test/chunk_1.15.2.bin differ diff --git a/test/chunk_1.16.1.bin b/test/chunk_1.16.1.bin new file mode 100644 index 0000000..86c296f Binary files /dev/null and b/test/chunk_1.16.1.bin differ diff --git a/test/chunk_1.16.2.bin b/test/chunk_1.16.2.bin new file mode 100644 index 0000000..520c2ce Binary files /dev/null and b/test/chunk_1.16.2.bin differ diff --git a/test/chunk_1.16.3.bin b/test/chunk_1.16.3.bin new file mode 100644 index 0000000..b615cc4 Binary files /dev/null and b/test/chunk_1.16.3.bin differ diff --git a/test/chunk_1.16.4.bin b/test/chunk_1.16.4.bin new file mode 100644 index 0000000..d911a12 Binary files /dev/null and b/test/chunk_1.16.4.bin differ diff --git a/test/chunk_1.16.bin b/test/chunk_1.16.bin new file mode 100644 index 0000000..406ab88 Binary files /dev/null and b/test/chunk_1.16.bin differ diff --git a/test/chunk_1.17.1.bin b/test/chunk_1.17.1.bin new file mode 100644 index 0000000..1993c75 Binary files /dev/null and b/test/chunk_1.17.1.bin differ diff --git a/test/chunk_1.18.1.bin b/test/chunk_1.18.1.bin new file mode 100644 index 0000000..1c46aa1 Binary files /dev/null and b/test/chunk_1.18.1.bin differ diff --git a/test/chunk_1.18.2.bin b/test/chunk_1.18.2.bin new file mode 100644 index 0000000..d601079 Binary files /dev/null and b/test/chunk_1.18.2.bin differ diff --git a/test/chunk_18w50a.bin b/test/chunk_18w50a.bin new file mode 100644 index 0000000..096ea7f Binary files /dev/null and b/test/chunk_18w50a.bin differ diff --git a/test/chunk_19w02a.bin b/test/chunk_19w02a.bin new file mode 100644 index 0000000..2eed386 Binary files /dev/null and b/test/chunk_19w02a.bin differ