| Crates.io | valve_pak |
| lib.rs | valve_pak |
| version | 0.1.0 |
| created_at | 2025-06-30 20:14:00.714488+00 |
| updated_at | 2025-06-30 20:14:00.714488+00 |
| description | A library and CLI tool for reading and writing Valve Pak files |
| homepage | https://github.com/floydya/valve-pak-rs |
| repository | https://github.com/floydya/valve-pak-rs |
| max_upload_size | |
| id | 1732330 |
| size | 101,291 |
A Rust library and command-line tool for reading, writing, and manipulating Valve Pak (VPK) files used by Valve's Source engine games.
git clone <repository-url>
cd valve-pak-rs
cargo build --release
The compiled binary will be available at target/release/valve_pak.
Add to your Cargo.toml:
cargo add valve_pak
valve_pak pack <directory> <output.vpk> [--verbose]
Example:
valve_pak pack my_mod/ my_mod.vpk --verbose
valve_pak unpack <input.vpk> <output_directory> [--verbose]
Example:
valve_pak unpack game_assets.vpk extracted/ --verbose
valve_pak list <input.vpk> [--detailed]
Examples:
valve_pak list game_assets.vpk
valve_pak list game_assets.vpk --detailed # Shows file sizes and CRC32
valve_pak verify <input.vpk>
Example:
valve_pak verify game_assets.vpk
valve_pak extract <input.vpk> <file_path> <output_file>
Example:
valve_pak extract game_assets.vpk scripts/game.txt extracted_game.txt
use valve_pak::{VPK, Result};
fn main() -> Result<()> {
// Open an existing VPK file
let vpk = VPK::open("game_assets.vpk")?;
// List all files
for file_path in vpk.file_paths() {
println!("{}", file_path);
}
// Get a specific file
let mut file = vpk.get_file("scripts/game.txt")?;
// Read file content
let content = file.read_all_string()?;
println!("File content: {}", content);
// Save file to disk
file.save("extracted_game.txt")?;
Ok(())
}
use valve_pak::{VPK, Result};
fn main() -> Result<()> {
// Create VPK from directory
let vpk = VPK::from_directory("my_mod/")?;
// Save to file
vpk.save("my_mod.vpk")?;
println!("Packed {} files", vpk.file_count());
Ok(())
}
use valve_pak::{VPK, Result};
use std::io::{Read, Seek, SeekFrom};
fn main() -> Result<()> {
let vpk = VPK::open("game_assets.vpk")?;
let mut file = vpk.get_file("textures/logo.png")?;
// VPKFile implements Read and Seek traits
let mut buffer = [0u8; 1024];
let bytes_read = file.read(&mut buffer)?;
// Seek to position
file.seek(SeekFrom::Start(100))?;
// Verify file integrity
if file.verify()? {
println!("File checksum is valid");
}
Ok(())
}
use valve_pak::{VPK, Result};
fn main() -> Result<()> {
match VPK::open("nonexistent.vpk") {
Ok(vpk) => {
println!("Opened VPK with {} files", vpk.file_count());
}
Err(e) => {
eprintln!("Failed to open VPK: {}", e);
// Error context is preserved through the chain
for cause in e.chain() {
eprintln!(" Caused by: {}", cause);
}
}
}
Ok(())
}
The library is optimized for performance:
All operations return Result<T> types with descriptive error messages using the anyhow crate. Errors include full context chains to help with debugging.
Run the test suite:
cargo test
Run tests with output:
cargo test -- --nocapture
anyhow - Error handling with contextclap - Command line argument parsingmd5 - MD5 checksum calculation (VPK v2)crc32fast - Fast CRC32 calculationwalkdir - Recursive directory traversalMIT License - see LICENSE file for details.