Skip to content

StarCitizenToolBox/unp4k_rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

unp4k_rs

A Rust implementation of unp4k - a tool for extracting and modifying Star Citizen .p4k files.

Note

The functionality to modify/create P4K is experimental; it is only used for testing local tools and cannot be verified by the game.

Project Structure

This project is organized as a Cargo workspace:

unp4k_rs/
├── src/                    # Core library (unp4k)
│   ├── lib.rs
│   ├── p4k.rs              # P4K archive reading
│   ├── p4k_writer.rs       # P4K archive writing
│   ├── cryxml.rs           # CryXML format conversion
│   ├── dataforge/          # DataForge/DCB format parser
│   └── ...
└── crates/
    ├── unp4k-cli/          # Command-line tool (unp4k-cli)
    │   └── src/main.rs
    └── dataforge-mcp/      # MCP server for DataForge (optional)
        └── src/
            ├── lib.rs
            ├── server.rs    # HTTP server with Streamable HTTP transport
            └── tools.rs     # MCP tool definitions

Installation

From Pre-built Binaries

Download the latest release from GitHub releases.

From Git

# Install CLI tool
cargo install --git https://github.com/StarCitizenToolBox/unp4k_rs.git unp4k-cli

From Source

git clone https://github.com/StarCitizenToolBox/unp4k_rs.git
cd unp4k_rs
cargo install --path crates/unp4k-cli

Verify Installation

unp4k --help

Features

  • 📦 Open and extract Star Citizen .p4k archives
  • ✏️ Create, modify and patch .p4k archives
  • 🔐 AES-128-CBC encryption/decryption support
  • 🗜️ Support for STORE, DEFLATE, and ZSTD compression
  • 📝 CryXML binary format to standard XML conversion
  • 📊 DataForge/DCB binary format to XML conversion
  • 📦 Socpak (.socpak) file extraction support
  • 🔍 Full-text search across DCB records
  • 💻 Cross-platform (Windows, macOS, Linux)

CLI Usage

Quick Extract (like original unp4k)

# Extract all files
unp4k Data.p4k

# Extract files matching a pattern
unp4k Data.p4k "*.xml"
unp4k Data.p4k "Data/Libs/*"

List Files

# List all files
unp4k list Data.p4k

# List files matching a pattern
unp4k list Data.p4k "*.dcb"

Extract Files

# Extract to current directory
unp4k extract Data.p4k

# Extract with pattern
unp4k extract Data.p4k "*.xml" -o ./output

# Extract and convert CryXML to standard XML
unp4k extract Data.p4k "*.xml" --convert-xml

# Extract with automatic socpak virtual directory mapping
unp4k extract Data.p4k --socpak-to-dir
# This enables transparent socpak handling:
# - .socpak files are mapped as .unsocpak/ virtual directories in memory
# - You can access files inside .socpak archives through virtual paths
# - Original .socpak files remain accessible
# Example: Data/Shaders/file.socpak becomes:
#   - Data/Shaders/file.socpak (original file)
#   - Data/Shaders/file.unsocpak/ (virtual directory with extracted contents)

Socpak Virtual File System

When opening a P4K with socpak_to_dir option enabled:

# .socpak files are automatically processed at open time
# Virtual directory structure is created in memory

How it works:

  • .socpak files are standard ZIP archives used by Star Citizen
  • With socpak_to_dir: true, .socpak files are transparently mapped as virtual directories:
    • Original: path/to/file.socpak
    • Virtual: path/to/file.unsocpak/ (contains extracted files)
    • Both are accessible through the normal P4K API
  • Lazy Loading: Files inside .socpak are NOT extracted at P4K open time
    • Virtual entries are created based on ZIP file listings
    • Actual extraction happens only when you access a file
    • Reduces memory usage and improves P4K open speed
  • No actual file system writes occur at open time
  • When extracting to disk, virtual directory structure is preserved

Example:

# Original P4K structure:
#   Data/Shaders/effects.socpak

# With --socpak-to-dir:
#   Data/Shaders/effects.socpak (original file)
#   Data/Shaders/effects.unsocpak/shader1.dxbc (virtual, extracted on first access)
#   Data/Shaders/effects.unsocpak/shader2.dxbc (virtual, extracted on first access)

Extract Socpak Files Independently

You can extract .socpak files directly without opening a P4K:

# Extract a single .socpak file
unp4k unsocpak file.socpak

# Extract to a specific directory
unp4k unsocpak file.socpak -o ./output

# Extract all .socpak files in a directory
unp4k unsocpak ./directory

# Recursively search and extract all .socpak files
unp4k unsocpak ./directory -r

# Overwrite existing files
unp4k unsocpak file.socpak -w

Show Archive Info

unp4k info Data.p4k

Create a P4K Archive

# Create a new P4K from a directory
unp4k pack output.p4k ./my_files

# With custom compression
unp4k pack output.p4k ./my_files -c zstd
unp4k pack output.p4k ./my_files -c deflate
unp4k pack output.p4k ./my_files -c store

# Without encryption
unp4k pack output.p4k ./my_files -e false

# With base path prefix
unp4k pack output.p4k ./my_files -b Data/MyMod

Patch an Existing P4K

# Patch a P4K with files from a directory
# Files in patch directory will replace matching files in the P4K
unp4k patch Data.p4k ./patches

# With base path prefix
unp4k patch Data.p4k ./patches -b Data/Localization

Add a Single File

# Add a file to the archive
unp4k add Data.p4k myfile.xml

# Add with custom archive path
unp4k add Data.p4k myfile.xml -a Data/Config/myfile.xml

Replace a Single File

# Replace a file in the archive (keeps original compression settings)
unp4k replace Data.p4k myfile.xml Data/Config/myfile.xml

Delete Files

# Delete files matching patterns
unp4k delete Data.p4k "*.tmp" "*.bak"

Convert DataForge/DCB to XML

# Show DCB file info
unp4k dcb Game.dcb --info

# Convert to separate XML files (like upstream unp4k)
unp4k dcb Game.dcb

# Convert to a single merged XML file
unp4k dcb Game.dcb --merge

# Specify output directory
unp4k dcb Game.dcb -o ./output

Start MCP Server for DataForge

The MCP (Model Context Protocol) server allows AI assistants to query and search DataForge/DCB data:

# Start MCP server on default port (3721)
unp4k mcp Game.dcb

# Start on custom port
unp4k mcp Game.dcb -p 8080

Available MCP Tools:

Tool Description
get_stats Get DataForge statistics and metadata
list_paths List record paths with keyword/regex filtering and pagination
get_content Get XML content of a specific record
batch_get_content Get XML content for multiple records (max 10)
search_in_paths Two-level filtering: path keyword + content keyword
full_text_search Search across all record paths and XML content
suggest_paths Path auto-completion based on prefix
list_directories Explore record hierarchy at different depths

Note: DataForge files can contain 50000+ records (GB-level data). Always use get_stats first to understand data size, and use count_only=true with pagination for large queries.

Library Usage

Add to your Cargo.toml:

[dependencies]
unp4k = { git = "https://github.com/StarCitizenToolBox/unp4k_rs.git" }

Reading P4K Archives

use unp4k::{P4kFile, CryXmlReader};

fn main() -> anyhow::Result<()> {
    // Open the archive
    let mut p4k = P4kFile::open("Data.p4k")?;
    
    // List entries
    for entry in p4k.entries() {
        println!("{}: {} bytes", entry.name, entry.uncompressed_size);
    }
    
    // Extract a file
    let data = p4k.extract("Data/Libs/Config/defaultProfile.xml")?;
    
    // Convert CryXML to standard XML
    if CryXmlReader::is_cryxml(&data) {
        let xml = CryXmlReader::parse(&data)?;
        println!("{}", xml);
    }
    
    Ok(())
}

Using Socpak Virtual File System

use unp4k::{P4kFile, P4kOpenOptions, EntrySource};

fn main() -> anyhow::Result<()> {
    // Open P4K with socpak virtual directory mapping enabled
    let options = P4kOpenOptions {
        socpak_to_dir: true,
    };
    let mut p4k = P4kFile::open_with_options("Data.p4k", options)?;
    
    // List all entries (includes both .socpak files and virtual .unsocpak/ directories)
    for entry in p4k.entries() {
        match &entry.source {
            EntrySource::P4k => {
                println!("P4K: {}", entry.name);
            }
            EntrySource::Socpak { parent_socpak, inner_path } => {
                println!("Virtual: {} (from {})", entry.name, parent_socpak);
            }
        }
    }
    
    // Access files inside .socpak archives transparently
    // If "Data/Shaders/effects.socpak" contains "shader.dxbc", you can access it as:
    let shader_data = p4k.extract("Data/Shaders/effects.unsocpak/shader.dxbc")?;
    
    // Or access the original .socpak file:
    let socpak_data = p4k.extract("Data/Shaders/effects.socpak")?;
    
    Ok(())
}

Creating and Modifying Archives

use unp4k::{P4kWriter, P4kWriteEntry, P4kWriteOptions, P4kModifier, CompressionMethod};

fn create_archive() -> anyhow::Result<()> {
    // Create a new P4K
    let mut writer = P4kWriter::create("my_archive.p4k")?;
    
    // Add entries
    let entry = P4kWriteEntry::new("Data/test.xml", b"<root/>".to_vec());
    writer.add_entry(entry)?;
    
    // Or add from file
    writer.add_file("local_file.txt", "Data/remote_file.txt")?;
    
    writer.finish()?;
    Ok(())
}

fn modify_archive() -> anyhow::Result<()> {
    // Open existing P4K for modification
    let mut modifier = P4kModifier::open("Data.p4k")?;
    
    // Add/replace a file
    modifier.add(P4kWriteEntry::new("Data/new_file.xml", b"<data/>".to_vec()));
    
    // Delete a file
    modifier.delete("Data/old_file.xml");
    
    // Save to new file
    modifier.save("Data_modified.p4k")?;
    Ok(())
}

DataForge/DCB Parsing

use unp4k::dataforge::{DataForge, search_records};

fn main() -> anyhow::Result<()> {
    let data = std::fs::read("Game.dcb")?;
    let df = DataForge::parse(&data)?;
    
    // List record paths
    for path in df.record_paths().take(10) {
        println!("{}", path);
    }
    
    // Convert a record to XML
    let xml = df.record_to_xml("path/to/record", true)?;
    println!("{}", xml);
    
    // Full-text search across all records
    let results = search_records(&df, "vehicle");
    for result in results {
        println!("Found in: {} ({} matches)", result.path, result.matches.len());
    }
    
    Ok(())
}

File Format

The .p4k files are encrypted ZIP archives with custom features:

  • Encryption: AES-128-CBC with a known public key (same as CryEngine)
  • Compression Methods:
    • STORE (0) - No compression
    • DEFLATE (8) - Standard ZIP compression
    • ZSTD (100) - Zstandard compression (custom extension)
  • CryXML: Binary XML format used for many game configuration files

Credits

  • Original unp4k by dolkensp
  • Star Citizen by Cloud Imperium Games

License

GNU GENERAL PUBLIC LICENSE Version 3

About

A Rust implementation of unp4k - a tools for extracting and modifying Star Citizen .p4k files.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages