Skip to content

Commit

Permalink
Merge pull request #123 from 0xnim/fix/optimizations
Browse files Browse the repository at this point in the history
Anvil Optimizations
  • Loading branch information
ReCore-sys authored Nov 13, 2024
2 parents 38f6acd + c31a5f3 commit 96379f1
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/lib/adapters/anvil/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ pub enum AnvilError {
UnableToReadFile(PathBuf, std::io::Error),
#[error("Unable to map file {0}: {1}")]
UnableToMapFile(PathBuf, std::io::Error),
#[error("Invalid offset or size")]
InvalidOffsetOrSize,
}
57 changes: 35 additions & 22 deletions src/lib/adapters/anvil/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,34 @@ impl LoadedAnvilFile {
/// can be used to get the chunk data with `get_chunk_from_location`. They are probably in order
/// but not guaranteed to be
pub fn get_locations(&self) -> Vec<u32> {
(0..1024).map(|i| {
u32::from(self.table[i * 4]) << 24
let mut locations = Vec::with_capacity(1024);
for i in 0..1024 {
let location = u32::from(self.table[i * 4]) << 24
| u32::from(self.table[i * 4 + 1]) << 16
| u32::from(self.table[i * 4 + 2]) << 8
| u32::from(self.table[i * 4 + 3])
})
.filter(|&x| x != 0)
.collect::<Vec<u32>>()
| u32::from(self.table[i * 4 + 3]);
if location != 0 {
locations.push(location);
}
}
locations
}

/// Get the data from the mmaped file, given an offset and size
#[allow(unsafe_code)]
fn get_data_from_file(&self, offset: u32, size: u32) -> Result<Vec<u8>, AnvilError> {
unsafe {
let start = self.data_map.as_ptr().add(offset as usize);
let slice = std::slice::from_raw_parts(start, size as usize);
Ok(slice.to_vec())
fn get_data_from_file(&self, offset: u32, size: u32) -> Result<&[u8], AnvilError> {
let offset = offset as usize;
let size = size as usize;

// Early return if the requested range is out of bounds
if offset + size > self.data_map.len() {
return Err(AnvilError::InvalidOffsetOrSize);
}

// Return a reference to the slice (no allocation needed)
Ok(&self.data_map[offset..offset + size])
}


/// Get the chunk data from a location
///
/// The location is a 32-bit integer, where the first 24 bits are the offset in the file, and the last 8 bits are the size of the chunk
Expand Down Expand Up @@ -152,17 +160,18 @@ impl LoadedAnvilFile {
let offset = offset * 4096;
let size = (location & 0xFF) * 4096;
let chunk_data = self.get_data_from_file(offset, size).ok()?;
let chunk_compressed_data = chunk_data[5..].to_vec();
let chunk_compressed_data = &chunk_data[5..]; // No need to clone, just use the slice
let compression_type = chunk_data[4];

match compression_type {
1 => {
let mut decompressed_data = Vec::new();
let mut decoder = flate2::read::GzDecoder::new(&chunk_compressed_data[..]);
let mut decoder = flate2::read::GzDecoder::new(chunk_compressed_data);
decoder.read_to_end(&mut decompressed_data).unwrap();
Some(decompressed_data)
}
2 => {
let out = yazi::decompress(&chunk_compressed_data[..], yazi::Format::Zlib).ok();
let out = yazi::decompress(chunk_compressed_data, yazi::Format::Zlib).ok();
match out {
Some(data) => {
match data.1 {
Expand All @@ -186,10 +195,10 @@ impl LoadedAnvilFile {
}
}
}
3 => Some(chunk_compressed_data),
3 => Some(chunk_compressed_data.to_vec()),
4 => {
let mut decompressed_data = vec![];
lzzzz::lz4::decompress(&chunk_compressed_data[..], &mut decompressed_data).ok()?;
lzzzz::lz4::decompress(chunk_compressed_data, &mut decompressed_data).ok()?;
Some(decompressed_data)
}
_ => {
Expand All @@ -205,11 +214,15 @@ impl LoadedAnvilFile {
///
/// This function will return the decompressed chunk data
pub fn get_chunk(&self, x: u32, z: u32) -> Option<Vec<u8>> {
let index = u64::from(4 * ((x % 32) + (z % 32) * 32));
let location = u32::from(self.table[index as usize * 4]) << 24
| u32::from(self.table[index as usize * 4 + 1]) << 16
| u32::from(self.table[index as usize * 4 + 2]) << 8
| u32::from(self.table[index as usize * 4 + 3]);
let index = u64::from(4 * ((x & 31) + (z & 31) * 32));
let base_index = index as usize * 4;
let chunk_data = [
u32::from(self.table[base_index]),
u32::from(self.table[base_index + 1]),
u32::from(self.table[base_index + 2]),
u32::from(self.table[base_index + 3]),
];
let location = (chunk_data[0] << 24) | (chunk_data[1] << 16) | (chunk_data[2] << 8) | chunk_data[3];
self.get_chunk_from_location(location)
}
}
Expand Down

0 comments on commit 96379f1

Please sign in to comment.