This code provides a utility for extracting files from Quake 3 game archives (.pk3
and .zip
) by defining functions to handle individual archive extraction (readPak
) and recursive extraction of multiple archives within a directory (extractPaks
). This utility enables users to access Quake 3 game assets and resources.
npm run import -- "unpack pk3s"
var StreamZip = require('node-stream-zip');
var fs = require('fs');
var path = require('path');
var importer = require('../Core');
var {globSync} = require('glob')
var mkdirpSync = importer.import("mkdirp")
async function readPak(zipFile, outdir) {
if(!outdir) {
outdir = '/Users/briancullinan/.q3a/unpacked/' + path.basename(zipFile) + 'dir'
}
const zip = new StreamZip.async({ file: zipFile, skipEntryNameValidation: true })
const entries = await zip.entries()
console.log(entries)
for (const entry of Object.values(entries)) {
var levelPath = path.join(outdir, entry.name).replace(/\\/g, '/')
if(fs.existsSync(levelPath)) continue
if(entry.isDirectory) continue
mkdirpSync(path.dirname(levelPath))
await zip.extract(entry.name, levelPath);
}
await zip.close();
}
async function extractPaks(inpaks, outdir) {
let root = path.resolve(path.dirname(inpaks))
var results = globSync('**', {cwd: root})
results.sort()
console.log(path.resolve(path.dirname(inpaks)), results)
for(let i = 0; i < results.length; i++) {
if(!results[i].match(/(\.pk3|\.zip)/))
continue
if(results[i].match(/\/|\\/))
await readPak(path.join(root, results[i]), path.join(outdir, path.dirname(results[i])))
else
await readPak(path.join(root, results[i]), outdir)
}
}
module.exports = extractPaks;
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const mkdirp = require('mkdirp');
const StreamZip = require('node-stream-zip');
// Function to read a PK3 file and extract its contents to a specified output directory
async function readPak(zipFile, outdir) {
// If output directory is not specified, generate a default one based on the zip file name
outdir = outdir || path.join('/Users/briancullinan/.q3a/unpacked/', path.basename(zipFile) + 'dir');
try {
// Create a new StreamZip instance with the zip file and skip entry name validation
const zip = new StreamZip.async({ file: zipFile, skipEntryNameValidation: true });
// Get the entries in the zip file
const entries = await zip.entries();
// Iterate over the entries
for (const entry of Object.values(entries)) {
// Construct the full path for the entry
const levelPath = path.join(outdir, entry.name).replace(/\\/g, '/');
// If the directory already exists, skip it
if (fs.existsSync(levelPath)) continue;
// If the entry is a directory, skip it
if (entry.isDirectory) continue;
// Create the directory for the entry if it doesn't exist
await mkdirp(path.dirname(levelPath));
// Extract the entry to the output directory
await zip.extract(entry.name, levelPath);
}
// Close the zip file
await zip.close();
} catch (error) {
// Log any errors that occur during the process
console.error(`Error reading PK3 file: ${error.message}`);
}
}
// Function to extract all PK3 and ZIP files in a directory and its subdirectories
async function extractPaks(inpaks, outdir) {
// Get the root directory of the input files
const root = path.resolve(path.dirname(inpaks));
// Get all files in the directory and its subdirectories
const results = glob.sync('**', { cwd: root });
// Sort the results
results.sort();
// Iterate over the results
for (const file of results) {
// Check if the file is a PK3 or ZIP file
if (!file.match(/(\.pk3|\.zip)/)) continue;
// If the file is a subdirectory, extract its PK3 files
if (file.match(/\/|\\/)) {
await readPak(path.join(root, file), path.join(outdir, path.dirname(file)));
} else {
// Otherwise, extract its PK3 files to the output directory
await readPak(path.join(root, file), outdir);
}
}
}
module.exports = extractPaks;
This code snippet defines two asynchronous functions, readPak
and extractPaks
, designed to extract files from Quake 3 game archives (.pk3
and .zip
files).
readPak
Function:
Initialization:
zipFile
(the archive to extract) and an optional outdir
(the output directory). If outdir
is not provided, it defaults to a directory named after the archive file.node-stream-zip
library to create a zip archive object.Extraction:
Cleanup:
extractPaks
Function:
Initialization:
inpaks
(the directory containing the archives) and an optional outdir
(the output directory).globSync
.Extraction Loop:
.pk3
or .zip
archives.readPak
to extract its contents.readPak
to extract the file directly.Export:
extractPaks
function as a module.Purpose:
This code snippet provides a utility for extracting files from Quake 3 game archives, allowing users to access individual game assets and resources.