Skip to main content
BSP files can contain embedded files in an internal ZIP archive called the pakfile. BSPSource can extract these files with optional smart filtering to exclude VBSP-generated content.

Understanding Pakfiles

The pakfile is a ZIP archive embedded in the BSP’s LUMP_PAKFILE lump. It typically contains:
  • Custom materials (.vmt, .vtf)
  • Custom models (.mdl, .vvd, .vtx, .phy)
  • Custom sounds (.wav, .mp3)
  • Particle manifests
  • VBSP-generated files (cubemaps, lighting data)

Basic Extraction

Extract All Files

config.unpackEmbedded = true;
config.smartUnpack = false; // Extract everything
This extracts the entire pakfile contents to the output directory.

Direct Pakfile Extraction

You can also extract the raw pakfile ZIP:
PakFile pakFile = new PakFile(bspFile);
pakFile.unpack(outputPath, true); // Direct ZIP extraction

Smart Unpacking

Smart unpacking filters out files automatically generated by VBSP, keeping only custom content:
config.unpackEmbedded = true;
config.smartUnpack = true; // Default: filter VBSP files

VBSP-Generated Files

BSPSource automatically detects and excludes these patterns: VHV Files (HDR lighting data):
sp_0.vhv
sp_1.vhv
sp_hdr_0.vhv
sp_hdr_1.vhv
Cubemap VTF Files:
c-64_128_256.vtf
c-64_128_256.hdr.vtf
Default Cubemaps:
cubemapdefault.vtf
cubemapdefault.hdr.vtf
Smart unpacking uses regex patterns to identify VBSP-generated files, preserving only mapper-created custom content.

Custom File Filtering

You can provide custom extraction filters:
PakFile pakFile = new PakFile(bspFile);

// Extract only materials
pakFile.unpack(outputPath, fileName -> 
    fileName.endsWith(".vmt") || fileName.endsWith(".vtf")
);

// Extract only models
pakFile.unpack(outputPath, fileName -> 
    fileName.endsWith(".mdl") || 
    fileName.endsWith(".vvd") || 
    fileName.endsWith(".vtx") || 
    fileName.endsWith(".phy")
);

// Exclude specific directories
pakFile.unpack(outputPath, fileName -> 
    !fileName.startsWith("maps/")
);

Extraction Features

Path Traversal Protection

BSPSource prevents malicious pakfiles from writing outside the extraction directory:
// Blocked: ../../../etc/passwd
// Allowed: materials/custom/wall.vtf
Files attempting path traversal are automatically skipped with warnings.

Invalid Path Handling

Files with invalid characters in their paths are skipped:
// Skipped: "file\x00name.txt" (contains null byte)

Duplicate File Protection

Existing files are never overwritten:
// If materials/wall.vtf exists, extraction is skipped

LZMA Compression Support

BSPSource supports LZMA-compressed pakfile entries (used in some Source 2007+ games):
  • Automatic LZMA detection
  • Proper decompression with EOS marker handling
  • Fallback for unsupported compression methods

Detection Functions

You can check if a file is VBSP-generated:
boolean isGenerated = PakFile.isVBSPGeneratedFile("c-64_128_256.vtf");
// Returns: true

boolean isGenerated = PakFile.isVBSPGeneratedFile("materials/custom/wall.vtf");
// Returns: false
Detection patterns:
// VHV pattern: sp(_hdr)?_\d+\.vhv
Pattern.compile("sp(_hdr)?_\\d+\\.vhv")

// Cubemap pattern: c(-?\d+)_(-?\d+)_(-?\d+)(\.hdr)?\.vtf
Pattern.compile("c(-?\\d+)_(-?\\d+)_(-?\\d+)(\\.hdr)?\\.vtf")

// Exact matches:
// - cubemapdefault.vtf
// - cubemapdefault.hdr.vtf

Configuration Examples

Extract Custom Content Only

BspSourceConfig config = new BspSourceConfig();
config.unpackEmbedded = true;
config.smartUnpack = true; // Filter out VBSP files

Extract Everything

BspSourceConfig config = new BspSourceConfig();
config.unpackEmbedded = true;
config.smartUnpack = false; // Include VBSP files

No Extraction

BspSourceConfig config = new BspSourceConfig();
config.unpackEmbedded = false;

Pakfile Structure

Typical pakfile contents:
pakfile.zip
├── materials/
│   ├── custom/
│   │   ├── wall.vmt
│   │   └── wall.vtf
│   └── maps/
│       └── mapname/
│           ├── c-64_128_256.vtf (VBSP)
│           └── cubemapdefault.vtf (VBSP)
├── models/
│   └── props/
│       ├── custom.mdl
│       ├── custom.vvd
│       └── custom.vtx
├── sound/
│   └── custom/
│       └── sound.wav
└── sp_0.vhv (VBSP)
With smartUnpack = true, only the custom files are extracted (excluding VBSP-generated files).

Error Handling

Missing Pakfile

try (ZipFile zip = pakFile.getZipFile()) {
    // Extract files
} catch (IOException ex) {
    // Pakfile broken or missing
}

Unsupported Compression

Files with unsupported compression methods are logged:
Cannot extract unsupported: file.txt| method: IMPLODE(6)| encryption: false

Invalid Entry Names

Skipped invalid_chars\x00.txt (contains invalid characters)

Working with Extracted Files

After extraction, custom content is organized by type:
output/
├── materials/
│   └── custom/
├── models/
│   └── props/
└── sound/
    └── custom/
You can then:
  1. Copy to your game’s directory structure
  2. Package into a custom content pack
  3. Include in a recompiled map

Advanced Usage

Extract Specific File Types

PakFile pakFile = new PakFile(bspFile);

// Materials only
pakFile.unpack(materialsPath, name -> 
    (name.endsWith(".vmt") || name.endsWith(".vtf")) &&
    !PakFile.isVBSPGeneratedFile(name)
);

// Models only
pakFile.unpack(modelsPath, name -> 
    name.startsWith("models/") &&
    (name.endsWith(".mdl") || name.endsWith(".vvd") || 
     name.endsWith(".vtx") || name.endsWith(".phy"))
);

Get ZipFile for Manual Processing

PakFile pakFile = new PakFile(bspFile);

try (ZipFile zip = pakFile.getZipFile()) {
    for (Enumeration<ZipArchiveEntry> e = zip.getEntries(); e.hasMoreElements();) {
        ZipArchiveEntry entry = e.nextElement();
        // Custom processing
    }
}
Some protected maps may include encrypted entity data (entities.dat) in the pakfile. See Protection Detection for details.

Build docs developers (and LLMs) love