UNPKG

bedrock-launcher-version-symlink-generator

Version:

A CLI to create symlinks for each of the version folders in Bedrock Launcher, so you can access the folders by version number instead of by UUID.

92 lines (83 loc) 4.27 kB
import chalk from "chalk"; import { exec, type ExecException } from "child_process"; import { existsSync, mkdirSync, readdirSync, readFileSync } from "fs"; import path from "path"; /** * The path to the user folder. * * This is the same folder you are sent to if your type `%AppData%/../../` in the `WIN+R` Run dialog. */ export const userFolderPath: string = import.meta.dirname.split(path.sep).slice(0, 3).join(path.sep); // Check if the user folder path is valid. if (!new RegExp(`[A-Z]:${path.sep === "\\" ? "\\\\" : path.sep}Users${path.sep === "\\" ? "\\\\" : path.sep}`).test(userFolderPath)) { console.error(chalk.red(`Invalid user folder path, please make sure this package is installed globally: "${userFolderPath}"`)); process.exit(1); } /** * The path to the Bedrock Launcher data folder. */ export const mcBedrockFolderPath: string = path.join(userFolderPath, "AppData/Roaming/.minecraft_bedrock"); // Check if Bedrock Launcher is installed. if (!existsSync(mcBedrockFolderPath)) { console.error(chalk.red(`Bedrock Launcher is not installed.`)); process.exit(1); } /** * The path to the Bedrock Launcher versions folder. */ const mcBedrockVersionsFolderPath: string = path.join(mcBedrockFolderPath, "versions"); /** * The list of folders for all the currently installed Minecraft Bedrock Edition versions. */ const bedrockLauncherVersionFolders: string[] = readdirSync(mcBedrockVersionsFolderPath).filter((versionFolder) => versionFolder.split("-").length === 5); /** * The list of version numbers. */ const versionNumbers: (`${number}.${number}.${number}.${number}_${"Release" | "Preview"}` | "Unable to determine version.")[] = bedrockLauncherVersionFolders.map((versionFolder) => { const AppxManifestXML: string = path.join(mcBedrockVersionsFolderPath, versionFolder, "AppxManifest.xml"); const AppxManifestXMLContent: string = readFileSync(AppxManifestXML, "utf-8"); const AppxManifestXMLVersion: string | undefined = AppxManifestXMLContent.match( /\<Identity Name="(?:Microsoft\.MinecraftUWP|Microsoft\.MinecraftWindowsBeta)" Publisher="[^"]*" Version="([\d\.]+)"/ )?.[1]; if (!AppxManifestXMLVersion) { return "Unable to determine version." as const; } const AppxManifestXMLEdition: "Minecraft for Windows" | "Minecraft Windows Preview" | undefined = AppxManifestXMLContent.match( /\<DisplayName\>(Minecraft for Windows|Minecraft Windows Preview)\<\/DisplayName>/ )?.[1] as "Minecraft for Windows" | "Minecraft Windows Preview" | undefined; const versionSegments = AppxManifestXMLVersion.split("."); return `${Number(versionSegments[0])}.${Number(versionSegments[1])}.${Number(versionSegments[2]?.slice(0, -2))}.${Number( versionSegments[2]?.slice(-2) )}_${AppxManifestXMLEdition === "Minecraft for Windows" ? "Release" : "Preview"}` as const; }); mkdirSync(path.join(mcBedrockFolderPath, "versionSymlinks"), { recursive: true }); for (let i = 0; i < bedrockLauncherVersionFolders.length; i++) { if (versionNumbers[i] === "Unable to determine version.") { console.warn(chalk.yellow(`Unable to determine version for folder "${bedrockLauncherVersionFolders[i]}". Skipping...`)); continue; } await runCommmand( `mklink /J "${path.join(mcBedrockFolderPath, "versionSymlinks", versionNumbers[i]!)}" "${path.join( mcBedrockVersionsFolderPath, bedrockLauncherVersionFolders[i]! )}"` ).then((r) => { if (r.err !== null) { throw r.err; } }); } /** * Runs a command. * * @param {string} command The command to run. * @returns A promise that resolves with the results of the command. */ export async function runCommmand(command: string): Promise<{ err: ExecException | null; stdout: string; stderr: string }> { return new Promise((resolve: (value: { err: ExecException | null; stdout: string; stderr: string }) => void) => { exec(command, (err: ExecException | null, stdout: string, stderr: string) => { resolve({ err, stdout, stderr }); }); }); }