resourcepacker
Version:
Package Minecraft resource packs easily and cleanly from a messy working directory
141 lines (140 loc) • 6.2 kB
JavaScript
;
const fs = require('fs');
const copyfiles = require('copyfiles');
const movefiles = require('glob-move');
const archiver = require('archiver');
const packFormat = require('pack-format');
const log = (msg) => console.log('<resourcepacker> ' + msg);
const CONFIG = {
configver: 2,
name: process.cwd().replace(/^.+[/\\]([^/\\]+)$/, '$1'),
packver: 'v1',
mcver: '1.16.5',
mcsnap: null,
description: 'Default resource pack configuration, which creates an automatic pack.mcmeta file when packing.',
languages: null,
files: [
"pack.png",
"pack.mcmeta",
"assets/**/*.png",
"assets/**/*.mcmeta",
"assets/**/*.json",
"assets/**/lang/**/*.lang",
"assets/**/texts/**/*.txt",
"assets/**/sounds/**/*.ogg",
"assets/**/shaders/**/*.fsh",
"assets/**/shaders/**/*.bin",
],
};
function init({ force } = { force: false }) {
if (fs.existsSync('.rpkr.json') && !force) {
log('Warning: This folder is already initialised with an .rpkr.json configuration file.');
log('Type `rpkr init force` to overwrite it with default settings.');
}
else
fs.writeFile('.rpkr.json', JSON.stringify(CONFIG, null, '\t'), (err) => {
if (err)
throw 'FSWriteError: Cannot write to .rpkr.json configuration file.';
else {
if (force)
log('Warning: Overwriting existing .rpkr.json configuration file.');
log(`Successfully created .rpkr.json configuration file with default settings.`);
}
});
}
function pack(input = '.', output, { zipped } = { zipped: true }) {
fs.readFile('.rpkr.json', 'utf8', (err, contents) => {
if (err)
init();
let config = err ? CONFIG : JSON.parse(contents);
let { name, packver, mcver, mcsnap, description, languages, files = CONFIG.files } = config;
// Create version label
let versionLabel = mcver;
if (mcsnap) {
if (mcsnap.match(/\d\dw\d\d\w/))
versionLabel = mcsnap; // snapshot
if (mcsnap.match(/\w+\d+/))
versionLabel = mcver + '-' + mcsnap; // short name of pre and rc
else
versionLabel = mcver + ' ' + mcsnap; // full name of pre and rc
}
output = output || `${name} ${packver} (${versionLabel})`;
// Create automatic mcmeta file
const mcmetaTemp = 'temp-pack.mcmeta';
if (description) {
const mcmetaContent = { pack: { pack_format: 0, description: '' } };
mcmetaContent.pack.pack_format = packFormat(versionLabel, 'resource') || packFormat(mcver, 'resource') || 0;
/// Compile description
for (const item in config) {
let escapedItem = item.replace(/[-\[\]{}().*+?^$\\\/|]/g, "\\$&");
description = description
.replace(/&([0-9a-fk-or])/g, '§$1') // formatting codes
.replace(RegExp(`<${escapedItem}>`, 'g'), config[item]); // custom parameters
}
mcmetaContent.pack.description = description;
/// Parse languages
if (languages) {
mcmetaContent.language = {};
for (const lang in languages) {
const matcher = /^\s*(.*?)\s*\((.*?)\)\s*/i;
let [, name, region] = languages[lang].match(matcher);
mcmetaContent.language[lang] = { name, region };
}
}
/// Write mcmeta to disc
if (!zipped || output.includes('/'))
fs.mkdirSync(output, { recursive: true });
fs.writeFileSync((zipped ? mcmetaTemp : output + '/pack.mcmeta'), JSON.stringify(mcmetaContent, null, '\t'), (err) => {
if (err)
log('FSWriteError: Could not create automatic pack.mcmeta file');
else
log('Created automatic pack.mcmeta file');
});
}
// Localise paths
for (let i in files) {
files[i] = input.replace(/\/$/, '') + '/' + files[i];
}
// Write output to disk
const success = function (s) {
const outFile = output.replace(/\/$|\.zip$/, '') + (zipped ? '.zip' : '/');
log(`${s ? 'S' : 'Uns'}uccessfully packaged version ${packver} of '${name}' for Minecraft ${mcver} to '${outFile}'`);
};
log(`Packaging version ${packver} of '${name}'...`);
if (zipped) {
const zipFilename = output + '.zip';
if (fs.existsSync(zipFilename))
log(`Warning: Overwriting existing file ${zipFilename}.`);
const outFile = fs.createWriteStream(zipFilename);
const zipFile = archiver('zip', { zlib: { level: 9 } });
outFile.on('close', function () {
fs.unlink(mcmetaTemp, (err) => err ? log(`Error: ${err}`) : success(true));
});
zipFile.pipe(outFile); // Start writing to zip file
zipFile.file(mcmetaTemp, { name: 'pack.mcmeta' });
for (let glob of [...files])
zipFile.glob(glob.replace(/^.\//, ''));
zipFile.finalize(); // End writing to zip file
}
else {
copyfiles([...files, output], {}, (err) => {
if (err) {
log(`Error: ${err}`);
success(false);
}
else if (input !== '.') {
const oldOutput = output + '/' + input;
movefiles(oldOutput + '/*', output)
.then(function () {
fs.rmdirSync(oldOutput);
success(true);
})
.catch((err) => log(`Error: ${err}`));
}
else
success(true);
});
}
});
}
module.exports = { init, pack };