pub struct RegionReader<'a, D = ()>where
D: CustomDecompression,{ /* private fields */ }Expand description
Implementations§
Source§impl<'a> RegionReader<'a, ()>
impl<'a> RegionReader<'a, ()>
Sourcepub fn new(data: &'a [u8]) -> Result<RegionReader<'a>, McaError>
pub fn new(data: &'a [u8]) -> Result<RegionReader<'a>, McaError>
Creates a new RegionReader with no CustomDecompression specified.
let mut region = RegionReader::new(REGION)?;
let chunk = region.chunk(5, 1)?;
Source§impl<'a, D: CustomDecompression> RegionReader<'a, D>
impl<'a, D: CustomDecompression> RegionReader<'a, D>
Sourcepub fn new_with_decompression(
data: &'a [u8],
custom_decompression: D,
) -> Result<RegionReader<'a, D>, McaError>
pub fn new_with_decompression( data: &'a [u8], custom_decompression: D, ) -> Result<RegionReader<'a, D>, McaError>
Creates a new RegionReader with a specified CustomDecompression scheme incase a non-vanilla compression byte appears.
Use RegionReader::new if you don’t need a CustomDecompression and any non-vanilla compression byte will return CompressionError::Unsupported.
§Error
Fails if the data given is less than 8192 bytes (minimum header size).
§Example
struct Custom;
impl CustomDecompression for Custom {
fn decompress(&self, data: &[u8], algorithm: &str, out: &mut Vec<u8>) -> Result<usize, CompressionError> {
// handle non-vanilla compression bytes ...
}
}
let mut region = RegionReader::new_with_decompression(REGION, Custom)?;
For a more concrete example, you can look at the tests in src/custom_compression.rs.
Sourcepub fn chunk(&mut self, x: u8, z: u8) -> Result<Option<&[u8]>, McaError>
pub fn chunk(&mut self, x: u8, z: u8) -> Result<Option<&[u8]>, McaError>
Returns the raw, uncompressed data for a chunk within a region.
Returns Ok(None) if the chunk isn’t present in the region (not generated yet).
§Example
let mut region = RegionReader::new(REGION)?;
let chunk = region.chunk(5, 24)?;
if let Some(chunk) = chunk {
// decode the raw chunk into nbt
// using something like "simdnbt" or "na_nbt"
}
Sourcepub fn chunk_data(
&self,
x: u8,
z: u8,
) -> Result<Option<ChunkDataRef<'a>>, McaError>
pub fn chunk_data( &self, x: u8, z: u8, ) -> Result<Option<ChunkDataRef<'a>>, McaError>
Returns the compressed data from the specified chunk.
Returns Ok(None) if the chunk isn’t present in the region (not generated yet).
You should prefer to use RegionReader::chunk instead as it also decompresses the data.
Since you cant use RegionReader::chunk in across threads, you’d have to use this and manually call RegionReader::decompress_data_ref.
See parallel example below
§Example
let mut region = RegionReader::new(REGION)?;
let chunk = region.chunk_data(5, 1)?;
if let Some(chunk) = chunk {
println!("compression: {:?}, size: {}", chunk.compression, chunk.data.as_ref().len());
}
§Parallel Example
let mut region = RegionReader::new(REGION)?;
// Get the total size of the uncompressed chunk data using rayon.
let sizes: Vec<usize> = (0..(REGION_SIZE * REGION_SIZE))
.into_par_iter()
.map(|s| {
let chunk = match region.chunk_data((s % 32) as u8, (s / 32) as u8)? {
Some(c) => c,
None => return Ok(0),
};
let mut uncompressed = Vec::new();
RegionReader::decompress_data_ref(
chunk.data,
chunk.compression,
&mut uncompressed,
&(),
)?;
Ok::<usize, McaError>(uncompressed.len())
})
.collect::<Result<Vec<usize>, McaError>>()
.unwrap();
let total: usize = sizes.iter().sum();
Sourcepub fn decompress_to_internal_buffer<'c>(
&'c mut self,
data: ChunkDataRef<'a>,
) -> Result<&'c [u8], McaError>
pub fn decompress_to_internal_buffer<'c>( &'c mut self, data: ChunkDataRef<'a>, ) -> Result<&'c [u8], McaError>
Decompresses a compressed chunk using the regions internal buffer to avoid allocation for decompression.
Look at RegionReader::decompress_data_ref for a standalone decompression function that this internally calls.
Sourcepub fn timestamp(&self, x: u8, z: u8) -> Result<u32, McaError>
pub fn timestamp(&self, x: u8, z: u8) -> Result<u32, McaError>
Returns the timestamp located within the region header for a specific chunk.
§Example
let mut region = RegionReader::new(REGION)?;
let timestamp = region.timestamp(2, 8)?;
let one_week: u32 = 604_800;
let recently_updated = timestamp > (current_timestamp() - one_week);
Sourcepub fn decompress_data_ref(
data: CompressedChunk<'_>,
compression: Compression,
buf: &mut Vec<u8>,
custom_decompression: &D,
) -> Result<(), CompressionError>
pub fn decompress_data_ref( data: CompressedChunk<'_>, compression: Compression, buf: &mut Vec<u8>, custom_decompression: &D, ) -> Result<(), CompressionError>
Decompresses data into buf, selecting a different decompression scheme depending on the compression byte
If the byte doesn’t match any of the vanilla minecraft compressions, it will call CustomDecompression::decompress.
By default, CustomDecompression is set to () and will immediately return CompressionError::Unsupported if the byte doesn’t match anything.
Sourcepub fn generated_chunks(&self) -> Result<Vec<(u8, u8)>, McaError>
pub fn generated_chunks(&self) -> Result<Vec<(u8, u8)>, McaError>
Returns all chunk coordinates where data exists within this region.
§Example
let mut region = RegionReader::new(REGION)?;
let generated_chunks = region.generated_chunks()?;
for ((x, z)) in generated_chunks {
let chunk = region.chunk(x, z)?
.expect("Chunk must exist since we iterate over generated chunks");
}
Sourcepub fn chunk_count(&self) -> Result<u16, McaError>
pub fn chunk_count(&self) -> Result<u16, McaError>
Returns how many chunks has been generated / has data within this region.
§Example
let mut region = RegionReader::new(REGION)?;
let chunk_count = region.chunk_count()?;
println!("{}/{} chunks generated", chunk_count, REGION_SIZE * REGION_SIZE);
Sourcepub fn iter(&'a self) -> Result<RegionIter<'a, D>, McaError>
pub fn iter(&'a self) -> Result<RegionIter<'a, D>, McaError>
Creates a RegionIter that iterates over all generated chunks within a region.
Makes it easy to generate over all valid chunks instead of having to manually index into all chunks, and then having to check if the chunk exists or not and only then use it.
§Example
let mut iter = region.iter()?;
while let Some(((x, z), chunk)) = iter.next_available_chunk()? {
println!("({x}, {z}) is {} bytes big", chunk.len());
}Source§impl<'a, D: CustomDecompression + Clone> RegionReader<'a, D>
impl<'a, D: CustomDecompression + Clone> RegionReader<'a, D>
Sourcepub fn into_writer<C: CustomCompression>(
&'a self,
custom_compression: C,
) -> Result<RegionWriter<'a, C>, McaError>
pub fn into_writer<C: CustomCompression>( &'a self, custom_compression: C, ) -> Result<RegionWriter<'a, C>, McaError>
Reads all chunks in this RegionReader, decompresses it and sets it inside a RegionWriter
Useful if you want to read in a region file and modify it, see example below on how.
§Example
let region = RegionReader::new(REGION)?;
// we give `()` to not specify any custom compression
let mut writer = region.into_writer(())?;
// switch the compression on chunk 8, 24 to Lz4
if let Some(chunk) = writer.chunk_mut(8, 24)? {
chunk.compression = Compression::Lz4;
}
let mut file = Vec::new();
writer.write(&mut file)?;Trait Implementations§
Source§impl<'a, D> Clone for RegionReader<'a, D>where
D: CustomDecompression + Clone,
impl<'a, D> Clone for RegionReader<'a, D>where
D: CustomDecompression + Clone,
Source§fn clone(&self) -> RegionReader<'a, D>
fn clone(&self) -> RegionReader<'a, D>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl<'a, D> Freeze for RegionReader<'a, D>where
D: Freeze,
impl<'a, D> RefUnwindSafe for RegionReader<'a, D>where
D: RefUnwindSafe,
impl<'a, D> Send for RegionReader<'a, D>
impl<'a, D> Sync for RegionReader<'a, D>
impl<'a, D> Unpin for RegionReader<'a, D>where
D: Unpin,
impl<'a, D> UnsafeUnpin for RegionReader<'a, D>where
D: UnsafeUnpin,
impl<'a, D> UnwindSafe for RegionReader<'a, D>where
D: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more