Skip to main content

RegionReader

Struct RegionReader 

Source
pub struct RegionReader<'a, D = ()>{ /* private fields */ }
Expand description

A representation of a Minecraft Region, used to read and decompress the format.

§Example

let mut region = RegionReader::new(REGION)?;

Implementations§

Source§

impl<'a> RegionReader<'a, ()>

Source

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>

Source

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.

Source

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"
}
Source

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();
Source

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.

Source

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);
Source

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.

Source

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");
}
Source

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);
Source

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>

Source

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>

Source§

fn clone(&self) -> RegionReader<'a, D>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<D: CustomDecompression + Debug> Debug for RegionReader<'_, D>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto 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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.