Merge pull request #44 from neocturne/hide-unknown-warnings

Hide unknown block/biome type warnings by default
This commit is contained in:
Matthias Schiffer 2024-01-10 13:14:59 +01:00 committed by GitHub
commit f08acd06e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 177 additions and 128 deletions

View file

@ -2,13 +2,22 @@
## [Unreleased] - ReleaseDate ## [Unreleased] - ReleaseDate
### Changed
- Without `--verbose`, only a single warning is printed at the end of
processing for unknown block/biome types, rather than once for every
section where such a block/biome is encountered.
## [2.0.2] - 2024-01-07 ## [2.0.2] - 2024-01-07
### Updated ### Added
- Added support for Minecraft 1.20.3+ - Added support for Minecraft 1.20.3+
Minecraft 1.20.3 renamed the `grass` block type to `short_grass`. Minecraft 1.20.3 renamed the `grass` block type to `short_grass`.
### Changed
- Updated [Leaflet](https://leafletjs.com/) to 1.9.4 - Updated [Leaflet](https://leafletjs.com/) to 1.9.4
- Updated attribution URL to https://github.com/neocturne/MinedMap - Updated attribution URL to https://github.com/neocturne/MinedMap

46
Cargo.lock generated
View file

@ -161,9 +161,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.13" version = "4.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642" checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -171,9 +171,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.12" version = "4.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -231,34 +231,28 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [ dependencies = [
"cfg-if",
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.17" version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [ dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.18" version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "either" name = "either"
@ -473,15 +467,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.151" version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]] [[package]]
name = "libz-ng-sys" name = "libz-ng-sys"
version = "1.1.12" version = "1.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dd9f43e75536a46ee0f92b758f6b63846e594e86638c61a9251338a65baea63" checksum = "81157dde2fd4ad2b45ea3a4bb47b8193b52a6346b678840d91d80d3c2cd166c5"
dependencies = [ dependencies = [
"cmake", "cmake",
"libc", "libc",
@ -713,9 +707,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.75" version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -784,9 +778,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.194" version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -802,9 +796,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.194" version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -1,6 +1,14 @@
//! The [RegionProcessor] and related functions //! The [RegionProcessor] and related functions
use std::{ffi::OsStr, path::PathBuf, sync::mpsc, time::SystemTime}; use std::{
ffi::OsStr,
path::PathBuf,
sync::{
atomic::{AtomicBool, Ordering},
mpsc,
},
time::SystemTime,
};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use rayon::prelude::*; use rayon::prelude::*;
@ -32,6 +40,8 @@ fn parse_region_filename(file_name: &OsStr) -> Option<TileCoords> {
enum RegionProcessorStatus { enum RegionProcessorStatus {
/// Region was processed /// Region was processed
Ok, Ok,
/// Region was processed, unknown blocks or biomes were encountered
OkWithUnknown,
/// Region was unchanged and skipped /// Region was unchanged and skipped
Skipped, Skipped,
/// Reading the region failed, previous processed data is reused /// Reading the region failed, previous processed data is reused
@ -68,6 +78,8 @@ struct SingleRegionProcessor<'a> {
processed_region: ProcessedRegion, processed_region: ProcessedRegion,
/// Lightmap intermediate data /// Lightmap intermediate data
lightmap: image::GrayAlphaImage, lightmap: image::GrayAlphaImage,
/// True if any unknown block or biome types were encountered during processing
has_unknown: bool,
} }
impl<'a> SingleRegionProcessor<'a> { impl<'a> SingleRegionProcessor<'a> {
@ -104,6 +116,7 @@ impl<'a> SingleRegionProcessor<'a> {
lightmap_needed, lightmap_needed,
processed_region, processed_region,
lightmap, lightmap,
has_unknown: false,
}) })
} }
@ -162,8 +175,10 @@ impl<'a> SingleRegionProcessor<'a> {
/// Processes a single chunk /// Processes a single chunk
fn process_chunk(&mut self, chunk_coords: ChunkCoords, data: world::de::Chunk) -> Result<()> { fn process_chunk(&mut self, chunk_coords: ChunkCoords, data: world::de::Chunk) -> Result<()> {
let chunk = world::chunk::Chunk::new(&data, self.block_types, self.biome_types) let (chunk, has_unknown) =
.with_context(|| format!("Failed to decode chunk {:?}", chunk_coords))?; world::chunk::Chunk::new(&data, self.block_types, self.biome_types)
.with_context(|| format!("Failed to decode chunk {:?}", chunk_coords))?;
self.has_unknown |= has_unknown;
let Some(layer::LayerData { let Some(layer::LayerData {
blocks, blocks,
biomes, biomes,
@ -231,7 +246,11 @@ impl<'a> SingleRegionProcessor<'a> {
self.save_region()?; self.save_region()?;
self.save_lightmap()?; self.save_lightmap()?;
Ok(RegionProcessorStatus::Ok) Ok(if self.has_unknown {
RegionProcessorStatus::OkWithUnknown
} else {
RegionProcessorStatus::Ok
})
} }
} }
@ -300,6 +319,8 @@ impl<'a> RegionProcessor<'a> {
let (processed_send, processed_recv) = mpsc::channel(); let (processed_send, processed_recv) = mpsc::channel();
let (error_send, error_recv) = mpsc::channel(); let (error_send, error_recv) = mpsc::channel();
let has_unknown = AtomicBool::new(false);
self.collect_regions()?.par_iter().try_for_each(|&coords| { self.collect_regions()?.par_iter().try_for_each(|&coords| {
let ret = self let ret = self
.process_region(coords) .process_region(coords)
@ -311,6 +332,10 @@ impl<'a> RegionProcessor<'a> {
match ret { match ret {
RegionProcessorStatus::Ok => processed_send.send(()).unwrap(), RegionProcessorStatus::Ok => processed_send.send(()).unwrap(),
RegionProcessorStatus::OkWithUnknown => {
has_unknown.store(true, Ordering::Relaxed);
processed_send.send(()).unwrap();
}
RegionProcessorStatus::Skipped => {} RegionProcessorStatus::Skipped => {}
RegionProcessorStatus::ErrorOk | RegionProcessorStatus::ErrorMissing => { RegionProcessorStatus::ErrorOk | RegionProcessorStatus::ErrorMissing => {
error_send.send(()).unwrap() error_send.send(()).unwrap()
@ -335,6 +360,16 @@ impl<'a> RegionProcessor<'a> {
errors, errors,
); );
if has_unknown.into_inner() {
warn!("Unknown block or biome types found during processing");
eprint!(concat!(
"\n",
" If you're encountering this issue with an unmodified Minecraft version supported by MinedMap,\n",
" please file a bug report including the output with the --verbose flag.\n",
"\n",
));
}
// Sort regions in a zig-zag pattern to optimize cache usage // Sort regions in a zig-zag pattern to optimize cache usage
regions.sort_unstable_by_key(|&TileCoords { x, z }| (x, if x % 2 == 0 { z } else { -z })); regions.sort_unstable_by_key(|&TileCoords { x, z }| (x, if x % 2 == 0 { z } else { -z }));

View file

@ -50,46 +50,13 @@ pub enum Chunk<'a> {
Empty, Empty,
} }
/// Inner data structure of [SectionIter]
#[derive(Debug, Clone)]
enum SectionIterInner<'a> {
/// Iterator over sections of [Chunk::V1_18]
V1_18 {
/// Inner iterator into section map
iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BiomesV1_18<'a>, BlockLight<'a>)>,
},
/// Iterator over sections of [Chunk::V1_13]
V1_13 {
/// Inner iterator into section map
iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BlockLight<'a>)>,
/// Chunk biome data
biomes: &'a BiomesV0<'a>,
},
/// Iterator over sections of [Chunk::V0]
V0 {
/// Inner iterator into section map
iter: btree_map::Iter<'a, SectionY, (SectionV0<'a>, BlockLight<'a>)>,
/// Chunk biome data
biomes: &'a BiomesV0<'a>,
},
/// Empty iterator over an unpopulated chunk ([Chunk::Empty])
Empty,
}
/// Iterator over the sections of a [Chunk]
#[derive(Debug, Clone)]
pub struct SectionIter<'a> {
/// Inner iterator enum
inner: SectionIterInner<'a>,
}
impl<'a> Chunk<'a> { impl<'a> Chunk<'a> {
/// Creates a new [Chunk] from a deserialized [de::Chunk] /// Creates a new [Chunk] from a deserialized [de::Chunk]
pub fn new( pub fn new(
data: &'a de::Chunk, data: &'a de::Chunk,
block_types: &'a BlockTypes, block_types: &'a BlockTypes,
biome_types: &'a BiomeTypes, biome_types: &'a BiomeTypes,
) -> Result<Self> { ) -> Result<(Self, bool)> {
let data_version = data.data_version.unwrap_or_default(); let data_version = data.data_version.unwrap_or_default();
match &data.chunk { match &data.chunk {
@ -108,8 +75,9 @@ impl<'a> Chunk<'a> {
sections: &'a Vec<de::SectionV1_18>, sections: &'a Vec<de::SectionV1_18>,
block_types: &'a BlockTypes, block_types: &'a BlockTypes,
biome_types: &'a BiomeTypes, biome_types: &'a BiomeTypes,
) -> Result<Self> { ) -> Result<(Self, bool)> {
let mut section_map = BTreeMap::new(); let mut section_map = BTreeMap::new();
let mut has_unknown = false;
for section in sections { for section in sections {
match &section.section { match &section.section {
@ -118,22 +86,27 @@ impl<'a> Chunk<'a> {
biomes, biomes,
block_light, block_light,
} => { } => {
let (loaded_section, unknown_blocks) = SectionV1_13::new(
data_version,
block_states.data.as_deref(),
&block_states.palette,
block_types,
)
.with_context(|| format!("Failed to load section at Y={}", section.y))?;
has_unknown |= unknown_blocks;
let (loaded_biomes, unknown_biomes) =
BiomesV1_18::new(biomes.data.as_deref(), &biomes.palette, biome_types)
.with_context(|| {
format!("Failed to load section biomes at Y={}", section.y)
})?;
has_unknown |= unknown_biomes;
section_map.insert( section_map.insert(
SectionY(section.y), SectionY(section.y),
( (
SectionV1_13::new( loaded_section,
data_version, loaded_biomes,
block_states.data.as_deref(),
&block_states.palette,
block_types,
)
.with_context(|| {
format!("Failed to load section at Y={}", section.y)
})?,
BiomesV1_18::new(biomes.data.as_deref(), &biomes.palette, biome_types)
.with_context(|| {
format!("Failed to load section biomes at Y={}", section.y)
})?,
BlockLight::new(block_light.as_deref()).with_context(|| { BlockLight::new(block_light.as_deref()).with_context(|| {
format!("Failed to load section block light at Y={}", section.y) format!("Failed to load section block light at Y={}", section.y)
})?, })?,
@ -144,7 +117,8 @@ impl<'a> Chunk<'a> {
}; };
} }
Ok(Chunk::V1_18 { section_map }) let chunk = Chunk::V1_18 { section_map };
Ok((chunk, has_unknown))
} }
/// [Chunk::new] implementation for all pre-1.18 chunk variants /// [Chunk::new] implementation for all pre-1.18 chunk variants
@ -153,9 +127,10 @@ impl<'a> Chunk<'a> {
level: &'a de::LevelV0, level: &'a de::LevelV0,
block_types: &'a BlockTypes, block_types: &'a BlockTypes,
biome_types: &'a BiomeTypes, biome_types: &'a BiomeTypes,
) -> Result<Self> { ) -> Result<(Self, bool)> {
let mut section_map_v1_13 = BTreeMap::new(); let mut section_map_v1_13 = BTreeMap::new();
let mut section_map_v0 = BTreeMap::new(); let mut section_map_v0 = BTreeMap::new();
let mut has_unknown = false;
for section in &level.sections { for section in &level.sections {
let block_light = let block_light =
@ -167,21 +142,13 @@ impl<'a> Chunk<'a> {
block_states, block_states,
palette, palette,
} => { } => {
section_map_v1_13.insert( let (loaded_section, unknown_blocks) =
SectionY(section.y.into()), SectionV1_13::new(data_version, Some(block_states), palette, block_types)
( .with_context(|| format!("Failed to load section at Y={}", section.y))?;
SectionV1_13::new( has_unknown |= unknown_blocks;
data_version,
Some(block_states), section_map_v1_13
palette, .insert(SectionY(section.y.into()), (loaded_section, block_light));
block_types,
)
.with_context(|| {
format!("Failed to load section at Y={}", section.y)
})?,
block_light,
),
);
} }
de::SectionV0Variant::V0 { blocks, data } => { de::SectionV0Variant::V0 { blocks, data } => {
section_map_v0.insert( section_map_v0.insert(
@ -199,23 +166,22 @@ impl<'a> Chunk<'a> {
} }
let biomes = BiomesV0::new(level.biomes.as_ref(), biome_types); let biomes = BiomesV0::new(level.biomes.as_ref(), biome_types);
let chunk = match (section_map_v1_13.is_empty(), section_map_v0.is_empty()) {
Ok( (true, true) => Chunk::Empty,
match (section_map_v1_13.is_empty(), section_map_v0.is_empty()) { (false, true) => Chunk::V1_13 {
(true, true) => Chunk::Empty, section_map: section_map_v1_13,
(false, true) => Chunk::V1_13 { biomes: biomes?,
section_map: section_map_v1_13,
biomes: biomes?,
},
(true, false) => Chunk::V0 {
section_map: section_map_v0,
biomes: biomes?,
},
(false, false) => {
bail!("Mixed section versions");
}
}, },
) (true, false) => Chunk::V0 {
section_map: section_map_v0,
biomes: biomes?,
},
(false, false) => {
bail!("Mixed section versions");
}
};
Ok((chunk, has_unknown))
} }
/// Returns true if the chunk does not contain any sections /// Returns true if the chunk does not contain any sections
@ -283,6 +249,39 @@ impl<'a, T> SectionIterTrait<'a> for T where
{ {
} }
/// Inner data structure of [SectionIter]
#[derive(Debug, Clone)]
enum SectionIterInner<'a> {
/// Iterator over sections of [Chunk::V1_18]
V1_18 {
/// Inner iterator into section map
iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BiomesV1_18<'a>, BlockLight<'a>)>,
},
/// Iterator over sections of [Chunk::V1_13]
V1_13 {
/// Inner iterator into section map
iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BlockLight<'a>)>,
/// Chunk biome data
biomes: &'a BiomesV0<'a>,
},
/// Iterator over sections of [Chunk::V0]
V0 {
/// Inner iterator into section map
iter: btree_map::Iter<'a, SectionY, (SectionV0<'a>, BlockLight<'a>)>,
/// Chunk biome data
biomes: &'a BiomesV0<'a>,
},
/// Empty iterator over an unpopulated chunk ([Chunk::Empty])
Empty,
}
/// Iterator over the sections of a [Chunk]
#[derive(Debug, Clone)]
pub struct SectionIter<'a> {
/// Inner iterator enum
inner: SectionIterInner<'a>,
}
impl<'a> SectionIter<'a> { impl<'a> SectionIter<'a> {
/// Helper to run a closure on the inner section iterator /// Helper to run a closure on the inner section iterator
fn with_iter<F, T>(&mut self, f: F) -> T fn with_iter<F, T>(&mut self, f: F) -> T

View file

@ -7,7 +7,7 @@ use std::fmt::Debug;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use num_integer::div_rem; use num_integer::div_rem;
use tracing::warn; use tracing::debug;
use super::de; use super::de;
use crate::{ use crate::{
@ -73,7 +73,7 @@ impl<'a> SectionV1_13<'a> {
block_states: Option<&'a [i64]>, block_states: Option<&'a [i64]>,
palette: &'a [de::BlockStatePaletteEntry], palette: &'a [de::BlockStatePaletteEntry],
block_types: &'a BlockTypes, block_types: &'a BlockTypes,
) -> Result<Self> { ) -> Result<(Self, bool)> {
let aligned_blocks = data_version >= 2529; let aligned_blocks = data_version >= 2529;
let bits = palette_bits(palette.len(), 4, 12).context("Unsupported block palette size")?; let bits = palette_bits(palette.len(), 4, 12).context("Unsupported block palette size")?;
@ -90,23 +90,29 @@ impl<'a> SectionV1_13<'a> {
} }
} }
let mut has_unknown = false;
let palette_types = palette let palette_types = palette
.iter() .iter()
.map(|entry| { .map(|entry| {
let block_type = block_types.get(&entry.name); let block_type = block_types.get(&entry.name);
if block_type.is_none() { if block_type.is_none() {
warn!("Unknown block type: {}", entry.name); debug!("Unknown block type: {}", entry.name);
has_unknown = true;
} }
block_type block_type
}) })
.collect(); .collect();
Ok(Self { Ok((
block_states, Self {
palette: palette_types, block_states,
bits, palette: palette_types,
aligned_blocks, bits,
}) aligned_blocks,
},
has_unknown,
))
} }
/// Looks up the block type palette index at the given coordinates /// Looks up the block type palette index at the given coordinates
@ -231,7 +237,7 @@ impl<'a> BiomesV1_18<'a> {
biomes: Option<&'a [i64]>, biomes: Option<&'a [i64]>,
palette: &'a [String], palette: &'a [String],
biome_types: &'a BiomeTypes, biome_types: &'a BiomeTypes,
) -> Result<Self> { ) -> Result<(Self, bool)> {
let bits = palette_bits(palette.len(), 1, 6).context("Unsupported block palette size")?; let bits = palette_bits(palette.len(), 1, 6).context("Unsupported block palette size")?;
if let Some(biomes) = biomes { if let Some(biomes) = biomes {
@ -242,22 +248,28 @@ impl<'a> BiomesV1_18<'a> {
} }
} }
let mut has_unknown = false;
let palette_types = palette let palette_types = palette
.iter() .iter()
.map(|entry| { .map(|entry| {
let biome_type = biome_types.get(entry); let biome_type = biome_types.get(entry);
if biome_type.is_none() { if biome_type.is_none() {
warn!("Unknown biome type: {}", entry); debug!("Unknown biome type: {}", entry);
has_unknown = true;
} }
biome_type biome_type
}) })
.collect(); .collect();
Ok(BiomesV1_18 { Ok((
biomes, BiomesV1_18 {
palette: palette_types, biomes,
bits, palette: palette_types,
}) bits,
},
has_unknown,
))
} }
/// Looks up the block type palette index at the given coordinates /// Looks up the block type palette index at the given coordinates