pub struct PatchChain { /* private fields */ }Expand description
A chain of MPQ archives with priority ordering
PatchChain manages multiple MPQ archives where files in higher-priority
archives override those in lower-priority ones. This mimics how World of Warcraft
handles its patch system, where patch-N.MPQ files override files in the base archives.
§Patch File Support
Starting with Cataclysm (4.x), WoW introduced binary patch files (PTCH format) that
contain binary diffs instead of complete files. PatchChain automatically detects
and applies these patches:
- Files with the
MPQ_FILE_PATCH_FILEflag are automatically recognized - Base file is located in lower-priority archives
- Patches are applied in order (lowest to highest priority)
- Both COPY (replacement) and BSD0 (binary diff) patches are supported
- MD5 verification ensures patch integrity
§Examples
use wow_mpq::PatchChain;
let mut chain = PatchChain::new();
// Add base archive with lowest priority
chain.add_archive("Data/common.MPQ", 0)?;
// Add patches with increasing priority
chain.add_archive("Data/patch.MPQ", 100)?;
chain.add_archive("Data/patch-2.MPQ", 200)?;
chain.add_archive("Data/patch-3.MPQ", 300)?;
// Extract file - will use the highest priority version available
// If the file exists as a PTCH patch file, it will be automatically applied
let data = chain.read_file("Interface/Icons/INV_Misc_QuestionMark.blp")?;Implementations§
Source§impl PatchChain
impl PatchChain
Sourcepub fn add_archive<P: AsRef<Path>>(
&mut self,
path: P,
priority: i32,
) -> Result<()>
pub fn add_archive<P: AsRef<Path>>( &mut self, path: P, priority: i32, ) -> Result<()>
Add an archive to the chain with a specific priority
Archives with higher priority values will override files in archives with lower priority values.
§Parameters
path: Path to the MPQ archivepriority: Priority value (higher = overrides lower)
§Typical priority values
- 0: Base archives (common.MPQ, expansion.MPQ)
- 100-999: Official patches (patch.MPQ, patch-2.MPQ, etc.)
- 1000+: Custom patches or mods
Sourcepub fn remove_archive<P: AsRef<Path>>(&mut self, path: P) -> Result<bool>
pub fn remove_archive<P: AsRef<Path>>(&mut self, path: P) -> Result<bool>
Remove an archive from the chain
Sourcepub fn archive_count(&self) -> usize
pub fn archive_count(&self) -> usize
Get the number of archives in the chain
Sourcepub fn read_file(&mut self, filename: &str) -> Result<Vec<u8>>
pub fn read_file(&mut self, filename: &str) -> Result<Vec<u8>>
Read a file from the chain
Returns the file from the highest-priority archive that contains it. If the file is a patch file, this method will automatically:
- Find the base file in lower-priority archives
- Apply all patches in priority order
- Return the fully patched result
Sourcepub fn contains_file(&self, filename: &str) -> bool
pub fn contains_file(&self, filename: &str) -> bool
Check if a file exists in the chain
Sourcepub fn find_file_archive(&self, filename: &str) -> Option<&Path>
pub fn find_file_archive(&self, filename: &str) -> Option<&Path>
Find which archive contains a file
Returns the path to the archive containing the file, or None if not found.
Sourcepub fn list(&mut self) -> Result<Vec<FileEntry>>
pub fn list(&mut self) -> Result<Vec<FileEntry>>
List all files in the chain
Returns a deduplicated list of all files across all archives, with file information from the highest-priority archive for each file.
Sourcepub fn get_chain_info(&mut self) -> Vec<ChainInfo>
pub fn get_chain_info(&mut self) -> Vec<ChainInfo>
Get information about all archives in the chain
Sourcepub fn extract_files(
&mut self,
filenames: &[&str],
) -> Vec<(String, Result<Vec<u8>>)>
pub fn extract_files( &mut self, filenames: &[&str], ) -> Vec<(String, Result<Vec<u8>>)>
Extract multiple files efficiently
This method extracts multiple files in a single pass, which can be more
efficient than calling read_file multiple times.
Sourcepub fn get_archive<P: AsRef<Path>>(&self, path: P) -> Option<&Archive>
pub fn get_archive<P: AsRef<Path>>(&self, path: P) -> Option<&Archive>
Get a reference to a specific archive by path
Sourcepub fn get_priority<P: AsRef<Path>>(&self, path: P) -> Option<i32>
pub fn get_priority<P: AsRef<Path>>(&self, path: P) -> Option<i32>
Get archive priority by path
Sourcepub fn from_archives_parallel<P: AsRef<Path> + Sync>(
archives: Vec<(P, i32)>,
) -> Result<Self>
pub fn from_archives_parallel<P: AsRef<Path> + Sync>( archives: Vec<(P, i32)>, ) -> Result<Self>
Load multiple archives in parallel and build a patch chain
This method loads all archives concurrently using rayon, then builds the patch chain with proper priority ordering. This is significantly faster than loading archives sequentially.
§Examples
use wow_mpq::PatchChain;
let archives = vec![
("Data/common.MPQ", 0),
("Data/patch.MPQ", 100),
("Data/patch-2.MPQ", 200),
("Data/patch-3.MPQ", 300),
];
let chain = PatchChain::from_archives_parallel(archives)?;Trait Implementations§
Source§impl Debug for PatchChain
impl Debug for PatchChain
Auto Trait Implementations§
impl Freeze for PatchChain
impl RefUnwindSafe for PatchChain
impl Send for PatchChain
impl Sync for PatchChain
impl Unpin for PatchChain
impl UnwindSafe for PatchChain
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> 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