use crate::backup::uncompress_backup; use crate::chunk_coordinate::ChunkCoordinate; use crate::error::Result; use anvil_region::position::{RegionChunkPosition, RegionPosition}; use anvil_region::provider::{FolderRegionProvider, RegionProvider}; use std::fs::remove_dir_all; use std::path::{Path, PathBuf}; /// Struct for manipulating a world from a backup struct RestoreAccess { /// Chunk source src_path: PathBuf, /// Chunk destination dest_path: PathBuf, } impl RestoreAccess { /// Create new RestoreAccess pub fn new(world_name: &str, src_path: &Path, dest_path: &Path) -> Result { let src_path = uncompress_backup(src_path)?.join(world_name).join("region"); let dest_path = dest_path.join(world_name).join("region"); Ok(RestoreAccess { src_path, dest_path, }) } /// Copy chunk from source to destination pub fn copy_chunk(&self, x: i32, z: i32) { let region_position = RegionPosition::from_chunk_position(x, z); let region_chunk_position = RegionChunkPosition::from_chunk_position(x, z); let src_provider = FolderRegionProvider::new(self.src_path.to_str().unwrap()); let dest_provider = FolderRegionProvider::new(self.dest_path.to_str().unwrap()); let mut src_region = src_provider.get_region(region_position).unwrap(); let src_chunk_compound_tag = src_region .read_chunk(region_chunk_position) .expect("Unable to load chunk"); let mut dst_region = dest_provider.get_region(region_position).unwrap(); dst_region .write_chunk(region_chunk_position, src_chunk_compound_tag) .expect("Unable to write chunk"); } /// Cleanup process pub fn cleanup(self) -> Result<()> { Ok(remove_dir_all("tmp")?) } } /// Restore a range of chunks from a backup pub fn restore_range_from_backup( world_name: &str, lower: ChunkCoordinate, upper: ChunkCoordinate, backup_path: &Path, minecraft_dir: &Path, ) -> Result { let chunk_access = RestoreAccess::new(world_name, backup_path, minecraft_dir)?; let mut count = 0; for x in lower.x..=upper.x { for z in lower.z..=upper.z { chunk_access.copy_chunk(x, z); count += 1; } } chunk_access.cleanup()?; Ok(count) } /// Restore a single chunk from a backup pub fn restore_chunk_from_backup( world_name: &str, chunk: ChunkCoordinate, backup_path: &Path, minecraft_dir: &Path, ) -> Result<()> { let chunk_access = RestoreAccess::new(world_name, backup_path, minecraft_dir)?; chunk_access.copy_chunk(chunk.x, chunk.z); chunk_access.cleanup()?; Ok(()) }