@origami-minecraft/devbuilds
Version:
Origami is a terminal-first Minecraft launcher that supports authentication, installation, and launching of Minecraft versions — with built-in support for Microsoft accounts, mod loaders, profile management, and more. Designed for power users, modders, an
754 lines • 36.9 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = __importDefault(require("child_process"));
const adm_zip_1 = __importDefault(require("adm-zip"));
const checksum_1 = __importDefault(require("checksum"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const utils_1 = require("./utils");
const handler_1 = require("../game/launch/handler");
const axios_1 = __importDefault(require("axios"));
const defaults_1 = require("../../config/defaults");
const https_1 = require("https");
const p_limit_1 = __importDefault(require("p-limit"));
const common_1 = require("../utils/common");
let counter = 0;
class Handler {
client;
options;
version;
agent;
limit;
constructor(client) {
this.version = "MCLC-undefined";
this.client = client;
this.options = client.options;
this.agent = new https_1.Agent({
keepAlive: false,
timeout: 50000,
maxSockets: this.options?.overrides?.maxSockets || 2,
});
this.limit = (0, p_limit_1.default)(this.options?.overrides?.connections || (0, common_1.getSafeConcurrencyLimit)());
}
checkJava(java) {
return new Promise(resolve => {
child_process_1.default.exec(`"${java}" -version`, (error, stdout, stderr) => {
if (error) {
resolve({
run: false,
message: error
});
}
else {
let version_match = stderr.match(/"(.*?)"/);
this.client.emit('debug', `[MCLC]: Using Java version ${chalk_1.default.green(version_match ? version_match.pop() : `Adoptium Temurin Java`)} ${stderr.includes('64-Bit') ? '64-bit' : '32-Bit'}`);
resolve({
run: true
});
}
});
});
}
async downloadAsync(url, directory, name = "Task", retry = true, type = "Download", maxRetries = 2) {
const targetPath = path_1.default.join(directory, name);
(0, common_1.ensureDir)(directory);
let attempt = 0;
while (attempt <= maxRetries) {
try {
const response = await (0, axios_1.default)({
url,
method: "GET",
responseType: "stream",
headers: {
"User-Agent": defaults_1.ORIGAMi_USER_AGENT,
},
httpAgent: this.agent,
httpsAgent: this.agent,
timeout: 50000,
maxContentLength: Infinity,
maxBodyLength: Infinity,
validateStatus: (status) => status < 400 // allow redirects
});
const totalBytes = parseInt(response.headers["content-length"] || "0", 10);
let receivedBytes = 0;
await new Promise((resolve, reject) => {
const fileStream = fs_1.default.createWriteStream(targetPath);
response.data.on("data", (chunk) => {
receivedBytes += chunk.length;
this.client.emit("download-status", {
name,
type,
current: receivedBytes,
total: totalBytes,
});
});
response.data.pipe(fileStream);
fileStream.on("finish", () => {
this.client.emit("download", name);
resolve();
});
fileStream.on("error", (err) => {
reject(err);
});
response.data.on("error", (err) => {
reject(err);
});
});
return true;
}
catch (err) {
this.client.emit("debug", `[DOWNLOADER]: Failed to download ${url} to ${targetPath}:\n${err.message}`);
if (fs_1.default.existsSync(targetPath))
fs_1.default.unlinkSync(targetPath);
attempt++;
if (attempt > maxRetries || !retry) {
return { failed: true, asset: null };
}
const wait = 500 * Math.pow(2, attempt - 1);
this.client.emit("debug", `[DOWNLOADER]: Retrying download (${attempt}/${maxRetries}) after ${wait}ms...`);
await new Promise(res => setTimeout(res, wait));
}
}
return { failed: true, asset: null };
}
checkSum(hash, file) {
return new Promise((resolve, _) => {
checksum_1.default.file(file, (err, sum) => {
if (err) {
this.client.emit('debug', `[MCLC]: Failed to check file hash due to ${err}`);
return resolve(false);
}
return resolve(hash === sum);
});
});
}
getVersion() {
return new Promise(async (resolve) => {
if (!this.options ||
!this.options.overrides ||
!this.options.directory ||
!this.options.overrides.url)
return resolve(null);
const versionJsonPath = this.options.overrides.versionJson || path_1.default.join(this.options.directory, `${this.options.version.number}.json`);
if (fs_1.default.existsSync(versionJsonPath)) {
this.version = JSON.parse(fs_1.default.readFileSync(versionJsonPath, { encoding: "utf-8" }));
return resolve(this.version);
}
const manifest = `${this.options.overrides.url.meta}/mc/game/version_manifest.json`;
const cache = this.options.cache ? `${this.options.cache}/json` : `${this.options.root}/cache/json`;
try {
this.version = await (0, utils_1.fetchVersionManifest)(this, manifest, cache);
return resolve(this.version);
}
catch (e) {
handler_1.logger.error(e.message);
process.exit(1);
}
});
}
async getJar() {
if (!this.options || !this.options.directory)
return;
await this.downloadAsync(this.version.downloads.client.url, this.options.directory, `${this.options.version.custom ? this.options.version.custom : this.options.version.number}.jar`, true, 'version-jar');
fs_1.default.writeFileSync(path_1.default.join(this.options.directory, `${this.options.version.number}.json`), JSON.stringify(this.version, null, 4));
return this.client.emit('debug', '[MCLC]: Downloaded vanilla `' + this.options.version.number + '`');
}
async getAssets() {
if (!this.options || !this.options.directory || !this.options.overrides || !this.options.overrides.url)
return;
const assetDirectory = path_1.default.resolve(this.options.overrides?.assetRoot || path_1.default.join(this.options.root, 'assets'));
const assetId = this.options.version.custom || this.options.version.number;
if (!fs_1.default.existsSync(path_1.default.join(assetDirectory, 'indexes', `${assetId}.json`))) {
await this.downloadAsync(this.version.assetIndex.url, path_1.default.join(assetDirectory, 'indexes'), `${assetId}.json`, true, 'asset-json');
}
const index = JSON.parse(fs_1.default.readFileSync(path_1.default.join(assetDirectory, 'indexes', `${assetId}.json`), { encoding: 'utf8' }));
this.client.emit('progress', {
type: 'assets',
task: 0,
total: Object.keys(index.objects).length
});
await (0, common_1.limitedAll)(Object.keys(index.objects).map(async (asset) => {
const hash = index.objects[asset].hash;
const subhash = hash.substring(0, 2);
const subAsset = path_1.default.join(assetDirectory, 'objects', subhash);
const assetPath = path_1.default.join(subAsset, hash);
const valid = fs_1.default.existsSync(assetPath) && await this.checkSum(hash, assetPath);
if (!valid) {
const result = await this.downloadAsync(`${this.options?.overrides?.url?.resource}/${subhash}/${hash}`, subAsset, hash, true, 'assets');
if (result === false || (typeof result === 'object' && result.failed)) {
this.client.emit('debug', `[MCLC]: Failed to download asset ${asset}, skipping...`);
return; // do not increment counter
}
}
counter++;
this.client.emit('progress', {
type: 'assets',
task: counter,
total: Object.keys(index.objects).length
});
}), this.limit);
this.client.emit('progress-end', {
type: 'assets',
task: counter,
total: Object.keys(index.objects).length
});
counter = 0;
if (this.isLegacy()) {
if (fs_1.default.existsSync(path_1.default.join(assetDirectory, 'legacy'))) {
this.client.emit('debug', '[MCLC]: The \'legacy\' directory is no longer used as Minecraft looks ' +
'for the resouces folder regardless of what is passed in the assetDirecotry launch option. I\'d ' +
`recommend removing the directory (${path_1.default.join(assetDirectory, 'legacy')})`);
}
const legacyDirectory = path_1.default.join(this.options.root, 'resources');
this.client.emit('debug', `[MCLC]: Copying assets over to ${legacyDirectory}`);
this.client.emit('progress', {
type: 'assets-copy',
task: 0,
total: Object.keys(index.objects).length
});
await Promise.all(Object.keys(index.objects).map(async (asset) => {
const hash = index.objects[asset].hash;
const subhash = hash.substring(0, 2);
const subAsset = path_1.default.join(assetDirectory, 'objects', subhash);
const legacyAsset = asset.split('/');
legacyAsset.pop();
if (!fs_1.default.existsSync(path_1.default.join(legacyDirectory, legacyAsset.join('/')))) {
fs_1.default.mkdirSync(path_1.default.join(legacyDirectory, legacyAsset.join('/')), { recursive: true });
}
if (!fs_1.default.existsSync(path_1.default.join(legacyDirectory, asset))) {
fs_1.default.copyFileSync(path_1.default.join(subAsset, hash), path_1.default.join(legacyDirectory, asset));
}
counter++;
this.client.emit('progress', {
type: 'assets-copy',
task: counter,
total: Object.keys(index.objects).length
});
}));
this.client.emit('progress-end', {
type: 'assets-copy',
task: counter,
total: Object.keys(index.objects).length
});
}
counter = 0;
this.client.emit('debug', '[MCLC]: Downloaded assets');
}
parseRule(lib) {
if (lib.rules) {
if (lib.rules.length > 1) {
if (lib.rules[0].action === 'allow' && lib.rules[1].action === 'disallow' && lib.rules[1].os.name === 'osx') {
return this.getOS() === 'osx';
}
return true;
}
else {
if (lib.rules[0].action === 'allow' && lib.rules[0].os)
return lib.rules[0].os.name !== this.getOS();
else
return false;
}
}
else {
return false;
}
}
async getNatives() {
if (!this.options || !this.options.directory || !this.options.overrides || !this.options.overrides.url)
return;
const nativeDirectory = path_1.default.resolve(this.options.overrides.natives || path_1.default.join(this.options.root, 'natives', this.version.id));
if (parseInt(this.version.id.split('.')[1]) >= 19)
return this.options.overrides.cwd || this.options.root;
if (!fs_1.default.existsSync(nativeDirectory) || !fs_1.default.readdirSync(nativeDirectory).length) {
fs_1.default.mkdirSync(nativeDirectory, { recursive: true });
const natives = async () => {
const natives = [];
await Promise.all(this.version.libraries.map(async (lib) => {
if (!lib.downloads || !lib.downloads.classifiers)
return;
if (this.parseRule(lib))
return;
const native = this.getOS() === 'osx'
? lib.downloads.classifiers['natives-osx'] || lib.downloads.classifiers['natives-macos']
: lib.downloads.classifiers[`natives-${this.getOS()}`];
natives.push(native);
}));
return natives;
};
const stat = await natives();
this.client.emit('progress', {
type: 'natives',
task: 0,
total: stat.length
});
await (0, common_1.limitedAll)(stat.map(async (native) => {
if (!native)
return;
const name = native.path.split('/').pop();
await this.downloadAsync(native.url, nativeDirectory, name, true, 'natives');
if (!await this.checkSum(native.sha1, path_1.default.join(nativeDirectory, name))) {
await this.downloadAsync(native.url, nativeDirectory, name, true, 'natives');
}
try {
new adm_zip_1.default(path_1.default.join(nativeDirectory, name)).extractAllTo(nativeDirectory, true);
}
catch (e) {
// Only doing a console.warn since a stupid error happens. You can basically ignore this.
// if it says Invalid file name, just means two files were downloaded and both were deleted.
// All is well.
handler_1.logger.warn(e.message);
}
fs_1.default.unlinkSync(path_1.default.join(nativeDirectory, name));
counter++;
this.client.emit('progress', {
type: 'natives',
task: counter,
total: stat.length
});
}), this.limit);
this.client.emit('progress-end', {
type: 'natives',
task: counter,
total: stat.length
});
this.client.emit('debug', '[MCLC]: Downloaded and extracted natives');
}
counter = 0;
this.client.emit('debug', `[MCLC]: Set native path to ${nativeDirectory}`);
return nativeDirectory;
;
}
fwAddArgs() {
if (!this.options)
return;
const forgeWrapperAgrs = [
`-Dforgewrapper.librariesDir=${path_1.default.resolve(this.options.overrides?.libraryRoot || path_1.default.join(this.options.root, 'libraries'))}`,
`-Dforgewrapper.installer=${this.options.forge}`,
`-Dforgewrapper.minecraft=${this.options.mcPath}`
];
this.options.customArgs
? this.options.customArgs = this.options.customArgs.concat(forgeWrapperAgrs)
: this.options.customArgs = forgeWrapperAgrs;
}
isModernForge(json) {
return json.inheritsFrom && json.inheritsFrom.split('.')[1] >= 12 && !(json.inheritsFrom === '1.12.2' && (json.id.split('.')[json.id.split('.').length - 1]) === '2847');
}
async getForgedWrapped() {
if (!this.options ||
!this.options.overrides ||
!this.options.overrides.fw ||
!this.options.overrides.url)
return;
let json = null;
let installerJson = null;
const versionPath = path_1.default.join(this.options.root, 'forge', `${this.version.id}`, 'version.json');
// Since we're building a proper "custom" JSON that will work nativly with MCLC, the version JSON will not
// be re-generated on the next run.
if (fs_1.default.existsSync(versionPath)) {
try {
json = JSON.parse(fs_1.default.readFileSync(versionPath, { encoding: "utf-8" }));
if (!json.forgeWrapperVersion || !(json.forgeWrapperVersion === this.options.overrides.fw.version)) {
this.client.emit('debug', '[MCLC]: Old ForgeWrapper has generated this version JSON, re-generating');
}
else {
// If forge is modern, add ForgeWrappers launch arguments and set forge to null so MCLC treats it as a custom json.
if (this.isModernForge(json)) {
this.fwAddArgs();
this.options.forge = undefined;
}
;
return json;
}
}
catch (e) {
handler_1.logger.warn(e.message);
this.client.emit('debug', '[MCLC]: Failed to parse Forge version JSON, re-generating');
}
}
this.client.emit('debug', '[MCLC]: Generating Forge version json, this might take a bit');
const zipFile = new adm_zip_1.default(this.options.forge);
json = zipFile.readAsText('version.json');
if (zipFile.getEntry('install_profile.json'))
installerJson = zipFile.readAsText('install_profile.json');
try {
json = JSON.parse(json);
if (installerJson)
installerJson = JSON.parse(installerJson);
}
catch (e) {
this.client.emit('debug', '[MCLC]: Failed to load json files for ForgeWrapper, using Vanilla instead');
return null;
}
// Adding the installer libraries as mavenFiles so MCLC downloads them but doesn't add them to the class paths.
if (installerJson) {
json.mavenFiles
? json.mavenFiles = json.mavenFiles.concat(installerJson.libraries)
: json.mavenFiles = installerJson.libraries;
}
// Holder for the specifc jar ending which depends on the specifc forge version.
let jarEnding = 'universal';
// We need to handle modern forge differently than legacy.
if (this.isModernForge(json)) {
// If forge is modern and above 1.12.2, we add ForgeWrapper to the libraries so MCLC includes it in the classpaths.
if (json.inheritsFrom !== '1.12.2') {
this.fwAddArgs();
const fwName = `ForgeWrapper-${this.options.overrides.fw.version}.jar`;
const fwPathArr = ['io', 'github', 'zekerzhayard', 'ForgeWrapper', this.options.overrides.fw.version];
json.libraries.push({
name: fwPathArr.join(':'),
downloads: {
artifact: {
path: [...fwPathArr, fwName].join('/'),
url: `${this.options.overrides.fw.baseUrl}${this.options.overrides.fw.version}/${fwName}`,
sha1: this.options.overrides.fw.sh1,
size: this.options.overrides.fw.size
}
}
});
json.mainClass = 'io.github.zekerzhayard.forgewrapper.installer.Main';
jarEnding = 'launcher';
// Providing a download URL to the universal jar mavenFile so it can be downloaded properly.
for (const library of json.mavenFiles) {
const lib = library.name.split(':');
if (lib[0] === 'net.minecraftforge' && lib[1].includes('forge')) {
library.downloads.artifact.url = this.options.overrides.url.mavenForge + library.downloads.artifact.path;
break;
}
}
}
else {
// Remove the forge dependent since we're going to overwrite the first entry anyways.
for (const library in json.mavenFiles) {
const lib = json.mavenFiles[library].name.split(':');
if (lib[0] === 'net.minecraftforge' && lib[1].includes('forge')) {
delete json.mavenFiles[library];
break;
}
}
}
}
else {
// Modifying legacy library format to play nice with MCLC's downloadToDirectory function.
await (0, common_1.limitedAll)(json.libraries.map(async (library) => {
const lib = library.name.split(':');
if (lib[0] === 'net.minecraftforge' && lib[1].includes('forge'))
return;
let url = this.options?.overrides?.url?.mavenForge;
const name = `${lib[1]}-${lib[2]}.jar`;
if (!library.url) {
if (library.serverreq || library.clientreq) {
url = this.options?.overrides?.url?.defaultRepoForge;
}
else {
return;
}
}
library.url = url;
const downloadLink = `${url}${lib[0].replace(/\./g, '/')}/${lib[1]}/${lib[2]}/${name}`;
// Checking if the file still exists on Forge's server, if not, replace it with the fallback.
// Not checking for sucess, only if it 404s.
try {
const response = await axios_1.default.get(downloadLink, { validateStatus: () => true }); // allow non-200s
if (response.status === 404) {
library.url = this.options?.overrides?.url?.fallbackMaven;
}
}
catch (error) {
this.client.emit('debug', `[MCLC]: Failed checking request for ${downloadLink}`);
}
}), this.limit);
}
// If a downloads property exists, we modify the inital forge entry to include ${jarEnding} so ForgeWrapper can work properly.
// If it doesn't, we simply remove it since we're already providing the universal jar.
if (json.libraries[0].downloads) {
const name = json.libraries[0].name;
if (name.includes('minecraftforge:forge') && !name.includes('universal')) {
json.libraries[0].name = name + `:${jarEnding}`;
json.libraries[0].downloads.artifact.path = json.libraries[0].downloads.artifact.path.replace('.jar', `-${jarEnding}.jar`);
json.libraries[0].downloads.artifact.url = this.options.overrides.url.mavenForge + json.libraries[0].downloads.artifact.path;
}
}
else {
delete json.libraries[0];
}
// Removing duplicates and null types
json.libraries = this.cleanUp(json.libraries);
if (json.mavenFiles)
json.mavenFiles = this.cleanUp(json.mavenFiles);
json.forgeWrapperVersion = this.options.overrides.fw.version;
// Saving file for next run!
if (!fs_1.default.existsSync(path_1.default.join(this.options.root, 'forge', this.version.id))) {
fs_1.default.mkdirSync(path_1.default.join(this.options.root, 'forge', this.version.id), { recursive: true });
}
fs_1.default.writeFileSync(versionPath, JSON.stringify(json, null, 4));
// Make MCLC treat modern forge as a custom version json rather then legacy forge.
if (this.isModernForge(json))
this.options.forge = undefined;
return json;
}
async downloadToDirectory(directory, libraries, eventName) {
const libs = [];
await (0, common_1.limitedAll)(libraries.map(async (library) => {
if (!library)
return;
if (this.parseRule(library))
return;
const lib = library.name.split(':');
let jarPath;
let name;
if (library.downloads && library.downloads.artifact && library.downloads.artifact.path) {
name = library.downloads.artifact.path.split('/')[library.downloads.artifact.path.split('/').length - 1];
jarPath = path_1.default.join(directory, this.popString(library.downloads.artifact.path));
}
else {
name = `${lib[1]}-${lib[2]}${lib[3] ? '-' + lib[3] : ''}.jar`;
jarPath = path_1.default.join(directory, `${lib[0].replace(/\./g, '/')}/${lib[1]}/${lib[2]}`);
}
const downloadLibrary = async (library) => {
if (library.url) {
const url = `${library.url}${lib[0].replace(/\./g, '/')}/${lib[1]}/${lib[2]}/${name}`;
await this.downloadAsync(url, jarPath, name, true, eventName);
}
else if (library.downloads && library.downloads.artifact && library.downloads.artifact.url) {
// Only download if there's a URL provided. If not, we're assuming it's going a generated dependency.
await this.downloadAsync(library.downloads.artifact.url, jarPath, name, true, eventName);
}
};
if (!fs_1.default.existsSync(path_1.default.join(jarPath, name)))
await downloadLibrary(library);
if (library.downloads && library.downloads.artifact) {
if (!this.checkSum(library.downloads.artifact.sha1, path_1.default.join(jarPath, name)))
await downloadLibrary(library);
}
counter++;
this.client.emit('progress', {
type: eventName,
task: counter,
total: libraries.length
});
libs.push(`${jarPath}${path_1.default.sep}${name}`);
}), this.limit);
this.client.emit('progress-end', {
type: eventName,
task: counter,
total: libraries.length
});
counter = 0;
return libs;
}
async getClasses(classJson) {
if (!this.options || !this.options.directory || !this.options.overrides)
return;
let libs = [];
const libraryDirectory = path_1.default.resolve(this.options.overrides.libraryRoot || path_1.default.join(this.options.root, 'libraries'));
if (classJson) {
if (classJson.mavenFiles) {
await this.downloadToDirectory(libraryDirectory, classJson.mavenFiles, 'classes-maven-custom');
}
libs = await this.downloadToDirectory(libraryDirectory, classJson.libraries, 'classes-custom');
}
const parsed = this.version.libraries.filter((lib) => {
if (lib.downloads && lib.downloads.artifact && !this.parseRule(lib)) {
if (!classJson || !classJson.libraries.some((l) => l.name.split(':')[1] === lib.name.split(':')[1])) {
return true;
}
}
return false;
});
libs = libs.concat((await this.downloadToDirectory(libraryDirectory, parsed, 'classes')));
counter = 0;
this.client.emit('debug', '[MCLC]: Collected class paths');
return libs;
}
popString(path) {
return path.split('/').slice(0, -1).join('/');
}
cleanUp(array) {
return [...new Set(Object.values(array).filter(value => value !== null))];
}
formatQuickPlay() {
if (!this.options || !this.options.quickPlay)
return;
const types = {
singleplayer: '--quickPlaySingleplayer',
multiplayer: '--quickPlayMultiplayer',
realms: '--quickPlayRealms',
legacy: null
};
const { type, identifier, path } = this.options.quickPlay;
const keys = Object.keys(types);
if (!keys.includes(type)) {
this.client.emit('debug', `[MCLC]: quickPlay type is not valid. Valid types are: ${keys.join(', ')}`);
return null;
}
const returnArgs = type === 'legacy'
? ['--server', identifier.split(':')[0], '--port', identifier.split(':')[1] || '25565']
: [types[type], identifier];
if (path)
returnArgs.push('--quickPlayPath', path);
return returnArgs;
}
async getLaunchOptions(modification) {
if (!this.options || !this.options.directory || !this.options.overrides)
return;
const type = Object.assign({}, this.version, modification);
let args = type.minecraftArguments
? type.minecraftArguments.split(' ')
: type.arguments.game;
const assetRoot = path_1.default.resolve(this.options.overrides.assetRoot || path_1.default.join(this.options.root, 'assets'));
const assetPath = this.isLegacy()
? path_1.default.join(this.options.root, 'resources')
: path_1.default.join(assetRoot);
const minArgs = this.options.overrides.minArgs || this.isLegacy() ? 5 : 11;
if (args.length < minArgs)
args = args.concat(this.version.minecraftArguments ? this.version.minecraftArguments.split(' ') : this.version.arguments.game);
if (this.options.customLaunchArgs)
args = args.concat(this.options.customLaunchArgs);
this.options.authorization = await Promise.resolve(this.options.authorization);
this.options.authorization.meta = this.options.authorization.meta ? this.options.authorization.meta : { type: 'mojang' };
const fields = {
'${auth_access_token}': this.options.authorization.access_token,
'${auth_session}': this.options.authorization.access_token,
'${auth_player_name}': this.options.authorization.name,
'${auth_uuid}': this.options.authorization.uuid,
'${auth_xuid}': this.options.authorization.meta.xuid || this.options.authorization.access_token,
'${user_properties}': this.options.authorization.user_properties,
'${user_type}': this.options.authorization.meta.type,
'${version_name}': this.options.overrides.versionName || this.options.version.number,
'${assets_index_name}': this.options.overrides.assetIndex || this.options.version.custom || this.options.version.number,
'${game_directory}': this.options.overrides.gameDirectory || this.options.root,
'${assets_root}': assetPath,
'${game_assets}': assetPath,
'${version_type}': this.options.version.type,
'${clientid}': this.options.authorization.meta.clientId || (this.options.authorization.client_token || this.options.authorization.access_token),
'${resolution_width}': this.options.window ? this.options.window.width : 856,
'${resolution_height}': this.options.window ? this.options.window.height : 482,
};
if (this.options.authorization.meta.demo && (this.options.features ? !this.options.features.includes('is_demo_user') : true)) {
args.push('--demo');
}
const replaceArg = (obj, index) => {
if (Array.isArray(obj.value)) {
for (const arg of obj.value) {
args.push(arg);
}
}
else {
args.push(obj.value);
}
delete args[index];
};
for (let index = 0; index < args.length; index++) {
if (typeof args[index] === 'object') {
if (args[index].rules) {
if (!this.options.features)
continue;
const featureFlags = [];
for (const rule of args[index].rules) {
featureFlags.push(...Object.keys(rule.features));
}
let hasAllRules = true;
for (const feature of this.options.features) {
if (!featureFlags.includes(feature)) {
hasAllRules = false;
}
}
if (hasAllRules)
replaceArg(args[index], index);
}
else {
replaceArg(args[index], index);
}
}
else {
if (Object.keys(fields).includes(args[index])) {
args[index] = fields[args[index]];
}
}
}
if (this.options.window) {
if (this.options.window.fullscreen) {
args.push('--fullscreen');
}
else {
if (this.options.window.width)
args.push('--width', this.options.window.width);
if (this.options.window.height)
args.push('--height', this.options.window.height);
}
}
if (this.options.quickPlay)
args = args.concat(this.formatQuickPlay());
if (this.options.proxy) {
args.push('--proxyHost', this.options.proxy.host, '--proxyPort', this.options.proxy.port || '8080', '--proxyUser', this.options.proxy.username, '--proxyPass', this.options.proxy.password);
}
args = args.filter(value => typeof value === 'string' || typeof value === 'number');
return args;
}
async getJVM() {
const opts = {
windows: '-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump',
osx: '-XstartOnFirstThread',
linux: '-Xss1M'
};
return opts[this.getOS()];
}
isLegacy() {
return this.version.assets === 'legacy' || this.version.assets === 'pre-1.6';
}
getOS() {
if (this.options?.os) {
return this.options.os;
}
else {
switch (process.platform) {
case 'win32': return 'windows';
case 'darwin': return 'osx';
default: return 'linux';
}
}
}
// To prevent launchers from breaking when they update. Will be reworked with rewrite.
getMemory() {
if (!this.options)
return;
if (!this.options.memory) {
this.client.emit('debug', '[MCLC]: Memory not set! Setting 1GB as MAX!');
this.options.memory = {
min: 512,
max: 1023
};
}
let isNaN_max = typeof this.options.memory.max === "number" ? isNaN(this.options.memory.max) : true;
let isNaN_min = typeof this.options.memory.min === "number" ? isNaN(this.options.memory.min) : true;
if (!isNaN_max && !isNaN_min) {
if (this.options.memory.max < this.options.memory.min) {
this.client.emit('debug', '[MCLC]: MIN memory is higher then MAX! Resetting!');
this.options.memory.max = 1023;
this.options.memory.min = 512;
}
return [`${this.options.memory.max}M`, `${this.options.memory.min}M`];
}
else {
return [`${this.options.memory.max}`, `${this.options.memory.min}`];
}
}
async extractPackage(options = this.options) {
if (!options || !options.clientPackage)
return;
if (options.clientPackage.startsWith('http')) {
await this.downloadAsync(options.clientPackage, options.root, 'clientPackage.zip', true, 'client-package');
options.clientPackage = path_1.default.join(options.root, 'clientPackage.zip');
}
new adm_zip_1.default(options.clientPackage).extractAllTo(options.root, true);
if (options.removePackage)
fs_1.default.unlinkSync(options.clientPackage);
return this.client.emit('package-extract', true);
}
}
exports.default = Handler;
//# sourceMappingURL=handler.js.map