Last active
July 16, 2024 22:17
-
-
Save 3vorp/311951a1e0f5125606d49941a296267a to your computer and use it in GitHub Desktop.
Convert a Minecraft resource pack between versions and editions with (relative) ease.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { copyFile, mkdir } = require("fs/promises"); | |
// why is there no async exists function | |
const { existsSync } = require("fs"); | |
const DEBUG = false; | |
if (!Object.groupBy || typeof Object.groupBy !== "function") { | |
console.error(`You need a newer version of Node.js to run this program! (>=21.0)`); | |
process.exit(1); | |
} | |
async function getLatestVersion(edition) { | |
const versions = await fetch(`https://api.faithfulpack.net/v2/settings/versions`).then((res) => | |
res.json(), | |
); | |
return versions[edition][0]; | |
} | |
async function generateConversionMap(inputEdition, outputEdition) { | |
const paths = await fetch("https://api.faithfulpack.net/v2/paths/raw") | |
.then((res) => res.json()) | |
.then((res) => Object.values(res)); | |
const uses = await fetch("https://api.faithfulpack.net/v2/uses/raw").then((res) => res.json()); | |
// add the edition to paths by taking parent use | |
const editionPaths = paths.map(({ name, use, versions }) => ({ | |
name, | |
versions, | |
texture: parseInt(use), | |
// object lookup is much faster than find | |
edition: uses[use].edition, | |
})); | |
// group paths by texture ID | |
const grouped = Object.groupBy(editionPaths, ({ texture }) => texture); | |
// group again by edition | |
return ( | |
Object.values(grouped) | |
.map((paths) => Object.groupBy(paths, ({ edition }) => edition)) | |
// check that all editions needed are present | |
.filter((obj) => obj[inputEdition]?.length && obj[outputEdition]?.length) | |
); | |
} | |
async function convertPack({ | |
inputDir, | |
outputDir, | |
inputEdition, | |
outputEdition, | |
inputVersion, | |
outputVersion, | |
}) { | |
// validation stuff | |
if (!inputDir || !outputDir) | |
return console.error("You need to specify input and output folders!"); | |
// if there's a version and no edition it's probably java | |
if (!inputEdition && inputVersion) inputEdition = "java"; | |
if (!outputEdition && outputVersion) outputEdition = "java"; | |
// if there's no version assume latest | |
if (!inputVersion || inputVersion === "latest") | |
inputVersion = await getLatestVersion(inputEdition); | |
if (!outputVersion || outputVersion === "latest") | |
outputVersion = await getLatestVersion(outputEdition); | |
console.log("Creating conversion map..."); | |
const conversionMap = await generateConversionMap(inputEdition, outputEdition); | |
console.log("Starting conversion process..."); | |
await Promise.all( | |
conversionMap.map((paths) => { | |
// get first match for version | |
const inputPath = paths[inputEdition].find((path) => | |
path.versions.includes(inputVersion), | |
); | |
if (!inputPath) return Promise.resolve(); | |
const imageToCopy = `${inputDir}/${inputPath.name}`; | |
// check that image exists before writing it | |
if (!existsSync(imageToCopy)) { | |
if (DEBUG) console.log(`Can't find ${imageToCopy}, skipping...`); | |
return Promise.resolve(); | |
} | |
return Promise.all( | |
paths[outputEdition] | |
// get all matching paths for version | |
.filter((path) => path.versions.includes(outputVersion)) | |
.map(({ name: outputPath }) => { | |
// create parent directory if it doesn't exist yet | |
const dir = `${outputDir}/${outputPath.slice( | |
0, | |
outputPath.lastIndexOf("/"), | |
)}`; | |
const prom = existsSync(dir) | |
? Promise.resolve() | |
: mkdir(dir, { recursive: true }); | |
return prom | |
.then(() => copyFile(imageToCopy, `${outputDir}/${outputPath}`)) | |
.then(() => { | |
if (DEBUG) console.log(`Copied ${inputPath.name} to ${outputPath}`); | |
}); | |
}), | |
); | |
}), | |
); | |
console.log(`Finished copying files to ${outputDir}!`); | |
} | |
// sample usage | |
convertPack({ | |
inputDir: "your/resource/pack/path/here", | |
outputDir: "./out", | |
inputEdition: "bedrock", // default: java | |
outputVersion: "1.8.9", // default: latest | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
NOTE: this has been moved into a proper repository at https://github.com/3vorp/convert-pack as a binary and library available on npm. This version will still work but won't be maintained anymore.