PatchChain

Struct PatchChain 

Source
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_FILE flag 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

Source

pub fn new() -> Self

Create a new empty patch chain

Source

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 archive
  • priority: 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
Source

pub fn remove_archive<P: AsRef<Path>>(&mut self, path: P) -> Result<bool>

Remove an archive from the chain

Source

pub fn clear(&mut self)

Clear all archives from the chain

Source

pub fn archive_count(&self) -> usize

Get the number of archives in the chain

Source

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:

  1. Find the base file in lower-priority archives
  2. Apply all patches in priority order
  3. Return the fully patched result
Source

pub fn contains_file(&self, filename: &str) -> bool

Check if a file exists in the chain

Source

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.

Source

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.

Source

pub fn get_chain_info(&mut self) -> Vec<ChainInfo>

Get information about all archives in the chain

Source

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.

Source

pub fn get_archive<P: AsRef<Path>>(&self, path: P) -> Option<&Archive>

Get a reference to a specific archive by path

Source

pub fn get_priority<P: AsRef<Path>>(&self, path: P) -> Option<i32>

Get archive priority by path

Source

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

pub fn add_archives_parallel<P: AsRef<Path> + Sync>( &mut self, archives: Vec<(P, i32)>, ) -> Result<()>

Add multiple archives to the chain in parallel

This method loads multiple archives concurrently and adds them to the existing chain with their specified priorities.

Source

pub fn set_priority<P: AsRef<Path>>( &mut self, path: P, new_priority: i32, ) -> Result<()>

Update the priority of an existing archive

Trait Implementations§

Source§

impl Debug for PatchChain

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Default for PatchChain

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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> 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> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V