Introduce ChunkArray type

A generic array for per-chunk data, indexed by ChunkCoords.
This commit is contained in:
Matthias Schiffer 2023-01-27 21:51:54 +01:00
parent 48e03aa266
commit 28b22ce423
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
4 changed files with 71 additions and 26 deletions

16
Cargo.lock generated
View file

@ -90,6 +90,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.2.8" version = "0.2.8"
@ -170,6 +176,15 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.139" version = "0.2.139"
@ -190,6 +205,7 @@ dependencies = [
"clap", "clap",
"fastnbt", "fastnbt",
"flate2", "flate2",
"itertools",
"serde", "serde",
] ]

View file

@ -12,4 +12,5 @@ anyhow = "1.0.68"
clap = { version = "4.1.4", features = ["derive"] } clap = { version = "4.1.4", features = ["derive"] }
fastnbt = "2.3.2" fastnbt = "2.3.2"
flate2 = "1.0.25" flate2 = "1.0.25"
itertools = "0.10.5"
serde = "1.0.152" serde = "1.0.152"

View file

@ -22,29 +22,19 @@ struct ChunkDesc {
fn parse_header(header: &[u8; BLOCKSIZE]) -> HashMap<u32, ChunkDesc> { fn parse_header(header: &[u8; BLOCKSIZE]) -> HashMap<u32, ChunkDesc> {
let mut map = HashMap::new(); let mut map = HashMap::new();
for z in 0..CHUNKS_PER_REGION { for coords in ChunkArray::<()>::keys() {
for x in 0..CHUNKS_PER_REGION { let chunk = &header[(4
let chunk = * (usize::from(CHUNKS_PER_REGION) * usize::from(coords.z.0)
&header[(4 * (usize::from(CHUNKS_PER_REGION) * usize::from(z) + usize::from(x)))..]; + usize::from(coords.x.0)))..];
let offset = u32::from(chunk[0]) << 16 | u32::from(chunk[1]) << 8 | u32::from(chunk[2]); let offset = u32::from(chunk[0]) << 16 | u32::from(chunk[1]) << 8 | u32::from(chunk[2]);
if offset == 0 { if offset == 0 {
continue; continue;
}
let len = chunk[3];
map.insert(
offset,
ChunkDesc {
coords: ChunkCoords {
x: ChunkX(x),
z: ChunkZ(z),
},
len,
},
);
} }
let len = chunk[3];
map.insert(offset, ChunkDesc { coords, len });
} }
map map
@ -100,7 +90,7 @@ impl<R: Read + Seek> Region<R> {
}; };
let mut index = 1; let mut index = 1;
let mut seen = [[false; CHUNKS_PER_REGION as usize]; CHUNKS_PER_REGION as usize]; let mut seen = ChunkArray::<bool>::default();
while !chunk_map.is_empty() { while !chunk_map.is_empty() {
let Some(ChunkDesc { coords, len }) = chunk_map.remove(&index) else { let Some(ChunkDesc { coords, len }) = chunk_map.remove(&index) else {
@ -109,11 +99,10 @@ impl<R: Read + Seek> Region<R> {
continue; continue;
}; };
let chunk_seen = &mut seen[coords.x.0 as usize][coords.z.0 as usize]; if seen[coords] {
if *chunk_seen {
bail!("Duplicate chunk"); bail!("Duplicate chunk");
} }
*chunk_seen = true; seen[coords] = true;
let mut buffer = vec![0; (len as usize) * BLOCKSIZE]; let mut buffer = vec![0; (len as usize) * BLOCKSIZE];
reader reader

View file

@ -1,4 +1,9 @@
use std::fmt::Debug; use std::{
fmt::Debug,
ops::{Index, IndexMut},
};
use itertools::iproduct;
pub const CHUNKS_PER_REGION: u8 = 32; pub const CHUNKS_PER_REGION: u8 = 32;
@ -22,3 +27,37 @@ impl Debug for ChunkCoords {
write!(f, "({}, {})", self.x.0, self.z.0) write!(f, "({}, {})", self.x.0, self.z.0)
} }
} }
#[derive(Debug, Clone, Copy, Default)]
pub struct ChunkArray<T>(pub [[T; CHUNKS_PER_REGION as usize]; CHUNKS_PER_REGION as usize]);
impl<T> ChunkArray<T> {
pub fn keys() -> impl Iterator<Item = ChunkCoords> {
iproduct!(0..CHUNKS_PER_REGION, 0..CHUNKS_PER_REGION).map(|(z, x)| ChunkCoords {
x: ChunkX(x),
z: ChunkZ(z),
})
}
pub fn values(&self) -> impl Iterator<Item = &T> {
Self::keys().map(|k| &self[k])
}
pub fn iter(&self) -> impl Iterator<Item = (ChunkCoords, &T)> {
Self::keys().map(|k| (k, &self[k]))
}
}
impl<T> Index<ChunkCoords> for ChunkArray<T> {
type Output = T;
fn index(&self, index: ChunkCoords) -> &Self::Output {
&self.0[index.z.0 as usize][index.x.0 as usize]
}
}
impl<T> IndexMut<ChunkCoords> for ChunkArray<T> {
fn index_mut(&mut self, index: ChunkCoords) -> &mut Self::Output {
&mut self.0[index.z.0 as usize][index.x.0 as usize]
}
}