From cca010ff69a1f88735bce9c29fe81d2513ccb5cf Mon Sep 17 00:00:00 2001 From: Kevand Date: Thu, 5 Feb 2026 13:52:01 +0000 Subject: [PATCH 1/4] Added necessary fields for Mojang Auth --- src/Authenticator/Mojang.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Authenticator/Mojang.ts b/src/Authenticator/Mojang.ts index f244f807..35b23647 100755 --- a/src/Authenticator/Mojang.ts +++ b/src/Authenticator/Mojang.ts @@ -14,8 +14,16 @@ async function login(username: string, password?: string) { return { access_token: UUID, client_token: UUID, - uuid: UUID, - name: username, + available_profiles: [ + { + id: UUID, + name: username + } + ], + selected_profile: { + id: UUID, + name: username + }, user_properties: '{}', meta: { online: false, @@ -47,8 +55,8 @@ async function login(username: string, password?: string) { let user = { access_token: message.accessToken, client_token: message.clientToken, - uuid: message.selectedProfile.id, - name: message.selectedProfile.name, + selected_profile: message.selectedProfile, + available_profiles: message.availableProfiles, user_properties: '{}', meta: { online: true, @@ -78,8 +86,7 @@ async function refresh(acc: any) { let user = { access_token: message.accessToken, client_token: message.clientToken, - uuid: message.selectedProfile.id, - name: message.selectedProfile.name, + selected_profile: message.selectedProfile, user_properties: '{}', meta: { online: true, From e377e055f48f90030dea017f238ae3d018b0f440 Mon Sep 17 00:00:00 2001 From: Kevand Date: Thu, 5 Feb 2026 14:17:35 +0000 Subject: [PATCH 2/4] Add availableProfiles support for launch arguments --- src/Minecraft/Minecraft-Arguments.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts index fc12d0ef..6d3ea8c5 100755 --- a/src/Minecraft/Minecraft-Arguments.ts +++ b/src/Minecraft/Minecraft-Arguments.ts @@ -158,8 +158,8 @@ export default class MinecraftArguments { const placeholderMap: Record = { '${auth_access_token}': this.authenticator.access_token, '${auth_session}': this.authenticator.access_token, - '${auth_player_name}': this.authenticator.name, - '${auth_uuid}': this.authenticator.uuid, + '${auth_player_name}': this.authenticator.selected_profile ? this.authenticator.selected_profile.name : this.authenticator.name, + '${auth_uuid}': this.authenticator.selected_profile ? this.authenticator.selected_profile.id : this.authenticator.uuid, '${auth_xuid}': this.authenticator?.xboxAccount?.xuid || this.authenticator.access_token, '${user_properties}': this.authenticator.user_properties, '${user_type}': userType, From 1b98b2f87a87c3097954554de7ae404038b07f7c Mon Sep 17 00:00:00 2001 From: Kevand Date: Sun, 8 Feb 2026 14:49:01 +0000 Subject: [PATCH 3/4] Added event when game is initialized --- src/Launch.ts | 820 +++++++++++++++++++++++++++----------------------- 1 file changed, 442 insertions(+), 378 deletions(-) diff --git a/src/Launch.ts b/src/Launch.ts index 6507febe..9ec6a914 100755 --- a/src/Launch.ts +++ b/src/Launch.ts @@ -3,404 +3,468 @@ * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -import { EventEmitter } from 'events'; -import path from 'path'; -import fs from 'fs'; -import { spawn } from 'child_process'; - -import jsonMinecraft from './Minecraft/Minecraft-Json.js'; -import librariesMinecraft from './Minecraft/Minecraft-Libraries.js'; -import assetsMinecraft from './Minecraft/Minecraft-Assets.js'; -import loggingMinecraft from './Minecraft/Minecraft-Logging.js'; -import loaderMinecraft from './Minecraft/Minecraft-Loader.js'; -import javaMinecraft from './Minecraft/Minecraft-Java.js'; -import bundleMinecraft from './Minecraft/Minecraft-Bundle.js'; -import argumentsMinecraft from './Minecraft/Minecraft-Arguments.js'; - -import { isold } from './utils/Index.js'; -import Downloader from './utils/Downloader.js'; +import { EventEmitter } from "events"; +import path from "path"; +import fs from "fs"; +import { spawn } from "child_process"; + +import jsonMinecraft from "./Minecraft/Minecraft-Json.js"; +import librariesMinecraft from "./Minecraft/Minecraft-Libraries.js"; +import assetsMinecraft from "./Minecraft/Minecraft-Assets.js"; +import loggingMinecraft from "./Minecraft/Minecraft-Logging.js"; +import loaderMinecraft from "./Minecraft/Minecraft-Loader.js"; +import javaMinecraft from "./Minecraft/Minecraft-Java.js"; +import bundleMinecraft from "./Minecraft/Minecraft-Bundle.js"; +import argumentsMinecraft from "./Minecraft/Minecraft-Arguments.js"; + +import { isold } from "./utils/Index.js"; +import Downloader from "./utils/Downloader.js"; type loader = { - /** - * Path to loader directory. Relative to absolute path to Minecraft's root directory (config option `path`). - * - * If `undefined`, defaults to `.minecraft/loader/`. - * - * Example: `'fabricfiles'`. - */ - path?: string, - /** - * Loader type. - * - * Acceptable values: `'forge'`, `'neoforge'`, `'fabric'`, `'legacyfabric'`, `'quilt'`. - */ - type?: string, - /** - * Loader build (version). - * - * Acceptable values: `'latest'`, `'recommended'`, actual version. - * - * Example: `'0.16.3'` - */ - build?: string, - /** - * Should the launcher use a loader? - */ - enable?: boolean -} + /** + * Path to loader directory. Relative to absolute path to Minecraft's root directory (config option `path`). + * + * If `undefined`, defaults to `.minecraft/loader/`. + * + * Example: `'fabricfiles'`. + */ + path?: string; + /** + * Loader type. + * + * Acceptable values: `'forge'`, `'neoforge'`, `'fabric'`, `'legacyfabric'`, `'quilt'`. + */ + type?: string; + /** + * Loader build (version). + * + * Acceptable values: `'latest'`, `'recommended'`, actual version. + * + * Example: `'0.16.3'` + */ + build?: string; + /** + * Should the launcher use a loader? + */ + enable?: boolean; +}; /** * Screen options. */ type screen = { - width?: number, - height?: number, - /** - * Should Minecraft be started in fullscreen mode? - */ - fullscreen?: boolean -} + width?: number; + height?: number; + /** + * Should Minecraft be started in fullscreen mode? + */ + fullscreen?: boolean; +}; /** * Memory limits */ type memory = { - /** - * Sets the `-Xms` JVM argument. This is the initial memory usage. - */ - min?: string, - /** - * Sets the `-Xmx` JVM argument. This is the limit of memory usage. - */ - max?: string -} + /** + * Sets the `-Xms` JVM argument. This is the initial memory usage. + */ + min?: string; + /** + * Sets the `-Xmx` JVM argument. This is the limit of memory usage. + */ + max?: string; +}; -/** +/** * Java download options */ type javaOPTS = { - /** - * Absolute path to Java binaries directory. - * - * If set, expects Java to be already downloaded. If `undefined`, downloads Java and sets it automatically. - * - * Example: `'C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\bin'` - */ - path?: string, - /** - * Java version number. - * - * If set, fetched from https://api.adoptium.net. - * If `undefined`, fetched from [Mojang](https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json). - * - * Example: `21` - */ - version?: string, - /** - * Java image type. Acceptable values: `'jdk'`, `'jre'`, `'testimage'`, `'debugimage'`, `'staticlibs'`, `'sources'`, `'sbom'`. - * - * Using `jre` is recommended since it only has what's needed. - */ - type: string -} + /** + * Absolute path to Java binaries directory. + * + * If set, expects Java to be already downloaded. If `undefined`, downloads Java and sets it automatically. + * + * Example: `'C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\bin'` + */ + path?: string; + /** + * Java version number. + * + * If set, fetched from https://api.adoptium.net. + * If `undefined`, fetched from [Mojang](https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json). + * + * Example: `21` + */ + version?: string; + /** + * Java image type. Acceptable values: `'jdk'`, `'jre'`, `'testimage'`, `'debugimage'`, `'staticlibs'`, `'sources'`, `'sbom'`. + * + * Using `jre` is recommended since it only has what's needed. + */ + type: string; +}; -/** +/** * Launch options. */ export type LaunchOPTS = { - /** - * URL to the launcher backend. Refer to [Selvania Launcher Wiki](https://github.com/luuxis/Selvania-Launcher/blob/master/docs/wiki_EN-US.md) for setup instructions. - */ - url?: string | null, - /** - * Something to Authenticate the player. - * - * Refer to `Mojang`, `Microsoft` or `AZauth` classes. - * - * Example: `await Mojang.login('Luuxis')` - */ - authenticator: any, - /** - * Connection timeout in milliseconds. - */ - timeout?: number, - /** - * Absolute path to Minecraft's root directory. - * - * Example: `'%appdata%/.minecraft'` - */ - path: string, - /** - * Minecraft version. - * - * Example: `'1.20.4'` - */ - version: string, - /** - * Path to instance directory. Relative to absolute path to Minecraft's root directory (config option `path`). - * This separates game files (e.g. versions, libraries, assets) from game data (e.g. worlds, resourcepacks, options). - * - * Example: `'PokeMoonX'` - */ - instance?: string, - /** - * Should Minecraft process be independent of launcher? - */ - detached?: boolean, - /** - * How many concurrent downloads can be in progress at once. - */ - downloadFileMultiple?: number, - /** - * Should the launcher bypass offline mode? - * - * If `true`, the launcher will not check if the user is online. - */ - bypassOffline?: boolean, - intelEnabledMac?: boolean, - /** - * Loader config - */ - loader: loader, - /** - * MCPathcer directory. (idk actually luuxis please verify this) - * - * If `instance` if set, relative to it. - * If `instance` is `undefined`, relative to `path`. - */ - mcp: any, - /** - * Should game files be verified each launch? - */ - verify: boolean, - /** - * Files to ignore from instance. (idk actually luuxis please verify this) - */ - ignored: string[], - /** - * Custom JVM arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#JVM_Arguments) - */ - JVM_ARGS: string[], - /** - * Custom game arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#Game_Arguments) - */ - GAME_ARGS: string[], - /** - * Java options. - */ - java: javaOPTS, - /** - * Screen options. - */ - screen: screen, - /** - * Memory limit options. - */ - memory: memory + /** + * URL to the launcher backend. Refer to [Selvania Launcher Wiki](https://github.com/luuxis/Selvania-Launcher/blob/master/docs/wiki_EN-US.md) for setup instructions. + */ + url?: string | null; + /** + * Something to Authenticate the player. + * + * Refer to `Mojang`, `Microsoft` or `AZauth` classes. + * + * Example: `await Mojang.login('Luuxis')` + */ + authenticator: any; + /** + * Connection timeout in milliseconds. + */ + timeout?: number; + /** + * Absolute path to Minecraft's root directory. + * + * Example: `'%appdata%/.minecraft'` + */ + path: string; + /** + * Minecraft version. + * + * Example: `'1.20.4'` + */ + version: string; + /** + * Path to instance directory. Relative to absolute path to Minecraft's root directory (config option `path`). + * This separates game files (e.g. versions, libraries, assets) from game data (e.g. worlds, resourcepacks, options). + * + * Example: `'PokeMoonX'` + */ + instance?: string; + /** + * Should Minecraft process be independent of launcher? + */ + detached?: boolean; + /** + * How many concurrent downloads can be in progress at once. + */ + downloadFileMultiple?: number; + /** + * Should the launcher bypass offline mode? + * + * If `true`, the launcher will not check if the user is online. + */ + bypassOffline?: boolean; + intelEnabledMac?: boolean; + /** + * Loader config + */ + loader: loader; + /** + * MCPathcer directory. (idk actually luuxis please verify this) + * + * If `instance` if set, relative to it. + * If `instance` is `undefined`, relative to `path`. + */ + mcp: any; + /** + * Should game files be verified each launch? + */ + verify: boolean; + /** + * Files to ignore from instance. (idk actually luuxis please verify this) + */ + ignored: string[]; + /** + * Custom JVM arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#JVM_Arguments) + */ + JVM_ARGS: string[]; + /** + * Custom game arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#Game_Arguments) + */ + GAME_ARGS: string[]; + /** + * Java options. + */ + java: javaOPTS; + /** + * Screen options. + */ + screen: screen; + /** + * Memory limit options. + */ + memory: memory; }; export default class Launch extends EventEmitter { - options: LaunchOPTS; - - async Launch(opt: LaunchOPTS) { - const defaultOptions: LaunchOPTS = { - url: null, - authenticator: null, - timeout: 10000, - path: '.Minecraft', - version: 'latest_release', - instance: null, - detached: false, - intelEnabledMac: false, - downloadFileMultiple: 5, - bypassOffline: false, - - loader: { - path: './loader', - type: null, - build: 'latest', - enable: false, - }, - - mcp: null, - - verify: false, - ignored: [], - JVM_ARGS: [], - GAME_ARGS: [], - - java: { - path: null, - version: null, - type: 'jre', - }, - - screen: { - width: null, - height: null, - fullscreen: false, - }, - - memory: { - min: '1G', - max: '2G' - }, - ...opt, - }; - - this.options = defaultOptions; - this.options.path = path.resolve(this.options.path).replace(/\\/g, '/'); - - if (this.options.mcp) { - if (this.options.instance) this.options.mcp = `${this.options.path}/instances/${this.options.instance}/${this.options.mcp}` - else this.options.mcp = path.resolve(`${this.options.path}/${this.options.mcp}`).replace(/\\/g, '/') - } - - if (this.options.loader.type) { - this.options.loader.type = this.options.loader.type.toLowerCase() - this.options.loader.build = this.options.loader.build.toLowerCase() - } - - if (!this.options.authenticator) return this.emit("error", { error: "Authenticator not found" }); - if (this.options.downloadFileMultiple < 1) this.options.downloadFileMultiple = 1 - if (this.options.downloadFileMultiple > 30) this.options.downloadFileMultiple = 30 - if (typeof this.options.loader.path !== 'string') this.options.loader.path = `./loader/${this.options.loader.type}`; - if (this.options.java.version && typeof this.options.java.type !== 'string') this.options.java.type = 'jre'; - this.start(); - } - - - async start() { - let data: any = await this.DownloadGame(); - if (data.error) return this.emit('error', data); - let { minecraftJson, minecraftLoader, minecraftVersion, minecraftJava } = data; - - let minecraftArguments: any = await new argumentsMinecraft(this.options).GetArguments(minecraftJson, minecraftLoader); - if (minecraftArguments.error) return this.emit('error', minecraftArguments); - - let loaderArguments: any = await new loaderMinecraft(this.options).GetArguments(minecraftLoader, minecraftVersion); - if (loaderArguments.error) return this.emit('error', loaderArguments); - - let Arguments: any = [ - ...minecraftArguments.jvm, - ...minecraftArguments.classpath, - ...loaderArguments.jvm, - minecraftArguments.mainClass, - ...minecraftArguments.game, - ...loaderArguments.game - ] - - let java: any = this.options.java.path ? this.options.java.path : minecraftJava.path; - let logs = this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path; - if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true }); - - let argumentsLogs: string = Arguments.join(' ') - argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.access_token, '????????') - argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.client_token, '????????') - argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.uuid, '????????') - argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.xboxAccount?.xuid, '????????') - argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, '') - this.emit('data', `Launching with arguments ${argumentsLogs}`); - - let minecraftDebug = spawn(java, Arguments, { cwd: logs, detached: this.options.detached }) - minecraftDebug.stdout.on('data', (data) => this.emit('data', data.toString('utf-8'))) - minecraftDebug.stderr.on('data', (data) => this.emit('data', data.toString('utf-8'))) - minecraftDebug.on('close', (code) => this.emit('close', 'Minecraft closed')) - } - - async DownloadGame() { - const InfoVersion = await new jsonMinecraft(this.options).GetInfoVersion(); - let loaderJson: any = null; - if ('error' in InfoVersion) return this.emit('error', InfoVersion); - - const { json, version } = InfoVersion; - - const libraries = new librariesMinecraft(this.options) - - const bundle = new bundleMinecraft(this.options) - const java = new javaMinecraft(this.options) - - java.on('progress', (progress: any, size: any, element: any) => { - this.emit('progress', progress, size, element) - }); - - java.on('extract', (progress: any) => { - this.emit('extract', progress) - }); - - const gameLibraries: any = await libraries.Getlibraries(json); - const gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url); - const gameAssets: any = await new assetsMinecraft(this.options).getAssets(json); - await new loggingMinecraft(this.options).getLogging(json); - const gameJava: any = this.options.java.path ? { files: [] } : await java.getJavaFiles(json); - - - if (gameJava.error) return gameJava - - const filesList: any = await bundle.checkBundle([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]); - - if (filesList.length > 0) { - let downloader = new Downloader(); - let totsize = await bundle.getTotalSize(filesList); - - downloader.on("progress", (DL: any, totDL: any, element: any) => { - this.emit("progress", DL, totDL, element); - }); - - downloader.on("speed", (speed: any) => { - this.emit("speed", speed); - }); - - downloader.on("estimated", (time: any) => { - this.emit("estimated", time); - }); - - downloader.on("error", (e: any) => { - this.emit("error", e); - }); - - await downloader.downloadFileMultiple(filesList, totsize, this.options.downloadFileMultiple, this.options.timeout); - } - - if (this.options.loader.enable === true) { - const loaderInstall = new loaderMinecraft(this.options) - - loaderInstall.on('extract', (extract: any) => { - this.emit('extract', extract); - }); - - loaderInstall.on('progress', (progress: any, size: any, element: any) => { - this.emit('progress', progress, size, element); - }); - - loaderInstall.on('check', (progress: any, size: any, element: any) => { - this.emit('check', progress, size, element); - }); - - loaderInstall.on('patch', (patch: any) => { - this.emit('patch', patch); - }); - - const jsonLoader = await loaderInstall.GetLoader(version, this.options.java.path ? this.options.java.path : gameJava.path) - .then((data: any) => data) - .catch((err: any) => err); - if (jsonLoader.error) return jsonLoader; - loaderJson = jsonLoader; - } - - if (this.options.verify) await bundle.checkFiles([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]); - - const natives = await libraries.natives(gameLibraries); - if (natives.length === 0) json.nativesList = false; - else json.nativesList = true; - - if (isold(json)) new assetsMinecraft(this.options).copyAssets(json); - - return { - minecraftJson: json, - minecraftLoader: loaderJson, - minecraftVersion: version, - minecraftJava: gameJava - } - } -} \ No newline at end of file + options: LaunchOPTS; + + async Launch(opt: LaunchOPTS) { + const defaultOptions: LaunchOPTS = { + url: null, + authenticator: null, + timeout: 10000, + path: ".Minecraft", + version: "latest_release", + instance: null, + detached: false, + intelEnabledMac: false, + downloadFileMultiple: 5, + bypassOffline: false, + + loader: { + path: "./loader", + type: null, + build: "latest", + enable: false, + }, + + mcp: null, + + verify: false, + ignored: [], + JVM_ARGS: [], + GAME_ARGS: [], + + java: { + path: null, + version: null, + type: "jre", + }, + + screen: { + width: null, + height: null, + fullscreen: false, + }, + + memory: { + min: "1G", + max: "2G", + }, + ...opt, + }; + + this.options = defaultOptions; + this.options.path = path.resolve(this.options.path).replace(/\\/g, "/"); + + if (this.options.mcp) { + if (this.options.instance) + this.options.mcp = `${this.options.path}/instances/${this.options.instance}/${this.options.mcp}`; + else + this.options.mcp = path + .resolve(`${this.options.path}/${this.options.mcp}`) + .replace(/\\/g, "/"); + } + + if (this.options.loader.type) { + this.options.loader.type = this.options.loader.type.toLowerCase(); + this.options.loader.build = this.options.loader.build.toLowerCase(); + } + + if (!this.options.authenticator) + return this.emit("error", { error: "Authenticator not found" }); + if (this.options.downloadFileMultiple < 1) + this.options.downloadFileMultiple = 1; + if (this.options.downloadFileMultiple > 30) + this.options.downloadFileMultiple = 30; + if (typeof this.options.loader.path !== "string") + this.options.loader.path = `./loader/${this.options.loader.type}`; + if (this.options.java.version && typeof this.options.java.type !== "string") + this.options.java.type = "jre"; + this.start(); + } + + async start() { + let data: any = await this.DownloadGame(); + if (data.error) return this.emit("error", data); + let { minecraftJson, minecraftLoader, minecraftVersion, minecraftJava } = + data; + + let minecraftArguments: any = await new argumentsMinecraft( + this.options, + ).GetArguments(minecraftJson, minecraftLoader); + if (minecraftArguments.error) return this.emit("error", minecraftArguments); + + let loaderArguments: any = await new loaderMinecraft( + this.options, + ).GetArguments(minecraftLoader, minecraftVersion); + if (loaderArguments.error) return this.emit("error", loaderArguments); + + let Arguments: any = [ + ...minecraftArguments.jvm, + ...minecraftArguments.classpath, + ...loaderArguments.jvm, + minecraftArguments.mainClass, + ...minecraftArguments.game, + ...loaderArguments.game, + ]; + + let java: any = this.options.java.path + ? this.options.java.path + : minecraftJava.path; + let logs = this.options.instance + ? `${this.options.path}/instances/${this.options.instance}` + : this.options.path; + if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true }); + + let argumentsLogs: string = Arguments.join(" "); + argumentsLogs = argumentsLogs.replaceAll( + this.options.authenticator?.access_token, + "????????", + ); + argumentsLogs = argumentsLogs.replaceAll( + this.options.authenticator?.client_token, + "????????", + ); + argumentsLogs = argumentsLogs.replaceAll( + this.options.authenticator?.uuid, + "????????", + ); + argumentsLogs = argumentsLogs.replaceAll( + this.options.authenticator?.xboxAccount?.xuid, + "????????", + ); + argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, ""); + this.emit("data", `Launching with arguments ${argumentsLogs}`); + + this.emit("loaded"); + let minecraftDebug = spawn(java, Arguments, { + cwd: logs, + detached: this.options.detached, + }); + minecraftDebug.stdout.on("data", (data) => + this.emit("data", data.toString("utf-8")), + ); + minecraftDebug.stderr.on("data", (data) => + this.emit("data", data.toString("utf-8")), + ); + minecraftDebug.on("close", (code) => + this.emit("close", "Minecraft closed"), + ); + } + + async DownloadGame() { + const InfoVersion = await new jsonMinecraft(this.options).GetInfoVersion(); + let loaderJson: any = null; + if ("error" in InfoVersion) return this.emit("error", InfoVersion); + + const { json, version } = InfoVersion; + + const libraries = new librariesMinecraft(this.options); + + const bundle = new bundleMinecraft(this.options); + const java = new javaMinecraft(this.options); + + java.on("progress", (progress: any, size: any, element: any) => { + this.emit("progress", progress, size, element); + }); + + java.on("extract", (progress: any) => { + this.emit("extract", progress); + }); + + const gameLibraries: any = await libraries.Getlibraries(json); + const gameAssetsOther: any = await libraries.GetAssetsOthers( + this.options.url, + ); + const gameAssets: any = await new assetsMinecraft(this.options).getAssets( + json, + ); + await new loggingMinecraft(this.options).getLogging(json); + const gameJava: any = this.options.java.path + ? { files: [] } + : await java.getJavaFiles(json); + + if (gameJava.error) return gameJava; + + const filesList: any = await bundle.checkBundle([ + ...gameLibraries, + ...gameAssetsOther, + ...gameAssets, + ...gameJava.files, + ]); + + if (filesList.length > 0) { + let downloader = new Downloader(); + let totsize = await bundle.getTotalSize(filesList); + + downloader.on("progress", (DL: any, totDL: any, element: any) => { + this.emit("progress", DL, totDL, element); + }); + + downloader.on("speed", (speed: any) => { + this.emit("speed", speed); + }); + + downloader.on("estimated", (time: any) => { + this.emit("estimated", time); + }); + + downloader.on("error", (e: any) => { + this.emit("error", e); + }); + + await downloader.downloadFileMultiple( + filesList, + totsize, + this.options.downloadFileMultiple, + this.options.timeout, + ); + } + + if (this.options.loader.enable === true) { + const loaderInstall = new loaderMinecraft(this.options); + + loaderInstall.on("extract", (extract: any) => { + this.emit("extract", extract); + }); + + loaderInstall.on("progress", (progress: any, size: any, element: any) => { + this.emit("progress", progress, size, element); + }); + + loaderInstall.on("check", (progress: any, size: any, element: any) => { + this.emit("check", progress, size, element); + }); + + loaderInstall.on("patch", (patch: any) => { + this.emit("patch", patch); + }); + + const jsonLoader = await loaderInstall + .GetLoader( + version, + this.options.java.path ? this.options.java.path : gameJava.path, + ) + .then((data: any) => data) + .catch((err: any) => err); + if (jsonLoader.error) return jsonLoader; + loaderJson = jsonLoader; + } + + if (this.options.verify) + await bundle.checkFiles([ + ...gameLibraries, + ...gameAssetsOther, + ...gameAssets, + ...gameJava.files, + ]); + + const natives = await libraries.natives(gameLibraries); + if (natives.length === 0) json.nativesList = false; + else json.nativesList = true; + + if (isold(json)) new assetsMinecraft(this.options).copyAssets(json); + + return { + minecraftJson: json, + minecraftLoader: loaderJson, + minecraftVersion: version, + minecraftJava: gameJava, + }; + } +} From 0f21f120b37a6a23ee7f32a61d7170fae3523f9d Mon Sep 17 00:00:00 2001 From: Kevand Date: Sun, 8 Feb 2026 15:05:35 +0000 Subject: [PATCH 4/4] Revert "Added event when game is initialized" This reverts commit 1b98b2f87a87c3097954554de7ae404038b07f7c. --- src/Launch.ts | 820 +++++++++++++++++++++++--------------------------- 1 file changed, 378 insertions(+), 442 deletions(-) diff --git a/src/Launch.ts b/src/Launch.ts index 9ec6a914..6507febe 100755 --- a/src/Launch.ts +++ b/src/Launch.ts @@ -3,468 +3,404 @@ * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -import { EventEmitter } from "events"; -import path from "path"; -import fs from "fs"; -import { spawn } from "child_process"; - -import jsonMinecraft from "./Minecraft/Minecraft-Json.js"; -import librariesMinecraft from "./Minecraft/Minecraft-Libraries.js"; -import assetsMinecraft from "./Minecraft/Minecraft-Assets.js"; -import loggingMinecraft from "./Minecraft/Minecraft-Logging.js"; -import loaderMinecraft from "./Minecraft/Minecraft-Loader.js"; -import javaMinecraft from "./Minecraft/Minecraft-Java.js"; -import bundleMinecraft from "./Minecraft/Minecraft-Bundle.js"; -import argumentsMinecraft from "./Minecraft/Minecraft-Arguments.js"; - -import { isold } from "./utils/Index.js"; -import Downloader from "./utils/Downloader.js"; +import { EventEmitter } from 'events'; +import path from 'path'; +import fs from 'fs'; +import { spawn } from 'child_process'; + +import jsonMinecraft from './Minecraft/Minecraft-Json.js'; +import librariesMinecraft from './Minecraft/Minecraft-Libraries.js'; +import assetsMinecraft from './Minecraft/Minecraft-Assets.js'; +import loggingMinecraft from './Minecraft/Minecraft-Logging.js'; +import loaderMinecraft from './Minecraft/Minecraft-Loader.js'; +import javaMinecraft from './Minecraft/Minecraft-Java.js'; +import bundleMinecraft from './Minecraft/Minecraft-Bundle.js'; +import argumentsMinecraft from './Minecraft/Minecraft-Arguments.js'; + +import { isold } from './utils/Index.js'; +import Downloader from './utils/Downloader.js'; type loader = { - /** - * Path to loader directory. Relative to absolute path to Minecraft's root directory (config option `path`). - * - * If `undefined`, defaults to `.minecraft/loader/`. - * - * Example: `'fabricfiles'`. - */ - path?: string; - /** - * Loader type. - * - * Acceptable values: `'forge'`, `'neoforge'`, `'fabric'`, `'legacyfabric'`, `'quilt'`. - */ - type?: string; - /** - * Loader build (version). - * - * Acceptable values: `'latest'`, `'recommended'`, actual version. - * - * Example: `'0.16.3'` - */ - build?: string; - /** - * Should the launcher use a loader? - */ - enable?: boolean; -}; + /** + * Path to loader directory. Relative to absolute path to Minecraft's root directory (config option `path`). + * + * If `undefined`, defaults to `.minecraft/loader/`. + * + * Example: `'fabricfiles'`. + */ + path?: string, + /** + * Loader type. + * + * Acceptable values: `'forge'`, `'neoforge'`, `'fabric'`, `'legacyfabric'`, `'quilt'`. + */ + type?: string, + /** + * Loader build (version). + * + * Acceptable values: `'latest'`, `'recommended'`, actual version. + * + * Example: `'0.16.3'` + */ + build?: string, + /** + * Should the launcher use a loader? + */ + enable?: boolean +} /** * Screen options. */ type screen = { - width?: number; - height?: number; - /** - * Should Minecraft be started in fullscreen mode? - */ - fullscreen?: boolean; -}; + width?: number, + height?: number, + /** + * Should Minecraft be started in fullscreen mode? + */ + fullscreen?: boolean +} /** * Memory limits */ type memory = { - /** - * Sets the `-Xms` JVM argument. This is the initial memory usage. - */ - min?: string; - /** - * Sets the `-Xmx` JVM argument. This is the limit of memory usage. - */ - max?: string; -}; + /** + * Sets the `-Xms` JVM argument. This is the initial memory usage. + */ + min?: string, + /** + * Sets the `-Xmx` JVM argument. This is the limit of memory usage. + */ + max?: string +} -/** +/** * Java download options */ type javaOPTS = { - /** - * Absolute path to Java binaries directory. - * - * If set, expects Java to be already downloaded. If `undefined`, downloads Java and sets it automatically. - * - * Example: `'C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\bin'` - */ - path?: string; - /** - * Java version number. - * - * If set, fetched from https://api.adoptium.net. - * If `undefined`, fetched from [Mojang](https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json). - * - * Example: `21` - */ - version?: string; - /** - * Java image type. Acceptable values: `'jdk'`, `'jre'`, `'testimage'`, `'debugimage'`, `'staticlibs'`, `'sources'`, `'sbom'`. - * - * Using `jre` is recommended since it only has what's needed. - */ - type: string; -}; + /** + * Absolute path to Java binaries directory. + * + * If set, expects Java to be already downloaded. If `undefined`, downloads Java and sets it automatically. + * + * Example: `'C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\bin'` + */ + path?: string, + /** + * Java version number. + * + * If set, fetched from https://api.adoptium.net. + * If `undefined`, fetched from [Mojang](https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json). + * + * Example: `21` + */ + version?: string, + /** + * Java image type. Acceptable values: `'jdk'`, `'jre'`, `'testimage'`, `'debugimage'`, `'staticlibs'`, `'sources'`, `'sbom'`. + * + * Using `jre` is recommended since it only has what's needed. + */ + type: string +} -/** +/** * Launch options. */ export type LaunchOPTS = { - /** - * URL to the launcher backend. Refer to [Selvania Launcher Wiki](https://github.com/luuxis/Selvania-Launcher/blob/master/docs/wiki_EN-US.md) for setup instructions. - */ - url?: string | null; - /** - * Something to Authenticate the player. - * - * Refer to `Mojang`, `Microsoft` or `AZauth` classes. - * - * Example: `await Mojang.login('Luuxis')` - */ - authenticator: any; - /** - * Connection timeout in milliseconds. - */ - timeout?: number; - /** - * Absolute path to Minecraft's root directory. - * - * Example: `'%appdata%/.minecraft'` - */ - path: string; - /** - * Minecraft version. - * - * Example: `'1.20.4'` - */ - version: string; - /** - * Path to instance directory. Relative to absolute path to Minecraft's root directory (config option `path`). - * This separates game files (e.g. versions, libraries, assets) from game data (e.g. worlds, resourcepacks, options). - * - * Example: `'PokeMoonX'` - */ - instance?: string; - /** - * Should Minecraft process be independent of launcher? - */ - detached?: boolean; - /** - * How many concurrent downloads can be in progress at once. - */ - downloadFileMultiple?: number; - /** - * Should the launcher bypass offline mode? - * - * If `true`, the launcher will not check if the user is online. - */ - bypassOffline?: boolean; - intelEnabledMac?: boolean; - /** - * Loader config - */ - loader: loader; - /** - * MCPathcer directory. (idk actually luuxis please verify this) - * - * If `instance` if set, relative to it. - * If `instance` is `undefined`, relative to `path`. - */ - mcp: any; - /** - * Should game files be verified each launch? - */ - verify: boolean; - /** - * Files to ignore from instance. (idk actually luuxis please verify this) - */ - ignored: string[]; - /** - * Custom JVM arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#JVM_Arguments) - */ - JVM_ARGS: string[]; - /** - * Custom game arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#Game_Arguments) - */ - GAME_ARGS: string[]; - /** - * Java options. - */ - java: javaOPTS; - /** - * Screen options. - */ - screen: screen; - /** - * Memory limit options. - */ - memory: memory; + /** + * URL to the launcher backend. Refer to [Selvania Launcher Wiki](https://github.com/luuxis/Selvania-Launcher/blob/master/docs/wiki_EN-US.md) for setup instructions. + */ + url?: string | null, + /** + * Something to Authenticate the player. + * + * Refer to `Mojang`, `Microsoft` or `AZauth` classes. + * + * Example: `await Mojang.login('Luuxis')` + */ + authenticator: any, + /** + * Connection timeout in milliseconds. + */ + timeout?: number, + /** + * Absolute path to Minecraft's root directory. + * + * Example: `'%appdata%/.minecraft'` + */ + path: string, + /** + * Minecraft version. + * + * Example: `'1.20.4'` + */ + version: string, + /** + * Path to instance directory. Relative to absolute path to Minecraft's root directory (config option `path`). + * This separates game files (e.g. versions, libraries, assets) from game data (e.g. worlds, resourcepacks, options). + * + * Example: `'PokeMoonX'` + */ + instance?: string, + /** + * Should Minecraft process be independent of launcher? + */ + detached?: boolean, + /** + * How many concurrent downloads can be in progress at once. + */ + downloadFileMultiple?: number, + /** + * Should the launcher bypass offline mode? + * + * If `true`, the launcher will not check if the user is online. + */ + bypassOffline?: boolean, + intelEnabledMac?: boolean, + /** + * Loader config + */ + loader: loader, + /** + * MCPathcer directory. (idk actually luuxis please verify this) + * + * If `instance` if set, relative to it. + * If `instance` is `undefined`, relative to `path`. + */ + mcp: any, + /** + * Should game files be verified each launch? + */ + verify: boolean, + /** + * Files to ignore from instance. (idk actually luuxis please verify this) + */ + ignored: string[], + /** + * Custom JVM arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#JVM_Arguments) + */ + JVM_ARGS: string[], + /** + * Custom game arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#Game_Arguments) + */ + GAME_ARGS: string[], + /** + * Java options. + */ + java: javaOPTS, + /** + * Screen options. + */ + screen: screen, + /** + * Memory limit options. + */ + memory: memory }; export default class Launch extends EventEmitter { - options: LaunchOPTS; - - async Launch(opt: LaunchOPTS) { - const defaultOptions: LaunchOPTS = { - url: null, - authenticator: null, - timeout: 10000, - path: ".Minecraft", - version: "latest_release", - instance: null, - detached: false, - intelEnabledMac: false, - downloadFileMultiple: 5, - bypassOffline: false, - - loader: { - path: "./loader", - type: null, - build: "latest", - enable: false, - }, - - mcp: null, - - verify: false, - ignored: [], - JVM_ARGS: [], - GAME_ARGS: [], - - java: { - path: null, - version: null, - type: "jre", - }, - - screen: { - width: null, - height: null, - fullscreen: false, - }, - - memory: { - min: "1G", - max: "2G", - }, - ...opt, - }; - - this.options = defaultOptions; - this.options.path = path.resolve(this.options.path).replace(/\\/g, "/"); - - if (this.options.mcp) { - if (this.options.instance) - this.options.mcp = `${this.options.path}/instances/${this.options.instance}/${this.options.mcp}`; - else - this.options.mcp = path - .resolve(`${this.options.path}/${this.options.mcp}`) - .replace(/\\/g, "/"); - } - - if (this.options.loader.type) { - this.options.loader.type = this.options.loader.type.toLowerCase(); - this.options.loader.build = this.options.loader.build.toLowerCase(); - } - - if (!this.options.authenticator) - return this.emit("error", { error: "Authenticator not found" }); - if (this.options.downloadFileMultiple < 1) - this.options.downloadFileMultiple = 1; - if (this.options.downloadFileMultiple > 30) - this.options.downloadFileMultiple = 30; - if (typeof this.options.loader.path !== "string") - this.options.loader.path = `./loader/${this.options.loader.type}`; - if (this.options.java.version && typeof this.options.java.type !== "string") - this.options.java.type = "jre"; - this.start(); - } - - async start() { - let data: any = await this.DownloadGame(); - if (data.error) return this.emit("error", data); - let { minecraftJson, minecraftLoader, minecraftVersion, minecraftJava } = - data; - - let minecraftArguments: any = await new argumentsMinecraft( - this.options, - ).GetArguments(minecraftJson, minecraftLoader); - if (minecraftArguments.error) return this.emit("error", minecraftArguments); - - let loaderArguments: any = await new loaderMinecraft( - this.options, - ).GetArguments(minecraftLoader, minecraftVersion); - if (loaderArguments.error) return this.emit("error", loaderArguments); - - let Arguments: any = [ - ...minecraftArguments.jvm, - ...minecraftArguments.classpath, - ...loaderArguments.jvm, - minecraftArguments.mainClass, - ...minecraftArguments.game, - ...loaderArguments.game, - ]; - - let java: any = this.options.java.path - ? this.options.java.path - : minecraftJava.path; - let logs = this.options.instance - ? `${this.options.path}/instances/${this.options.instance}` - : this.options.path; - if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true }); - - let argumentsLogs: string = Arguments.join(" "); - argumentsLogs = argumentsLogs.replaceAll( - this.options.authenticator?.access_token, - "????????", - ); - argumentsLogs = argumentsLogs.replaceAll( - this.options.authenticator?.client_token, - "????????", - ); - argumentsLogs = argumentsLogs.replaceAll( - this.options.authenticator?.uuid, - "????????", - ); - argumentsLogs = argumentsLogs.replaceAll( - this.options.authenticator?.xboxAccount?.xuid, - "????????", - ); - argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, ""); - this.emit("data", `Launching with arguments ${argumentsLogs}`); - - this.emit("loaded"); - let minecraftDebug = spawn(java, Arguments, { - cwd: logs, - detached: this.options.detached, - }); - minecraftDebug.stdout.on("data", (data) => - this.emit("data", data.toString("utf-8")), - ); - minecraftDebug.stderr.on("data", (data) => - this.emit("data", data.toString("utf-8")), - ); - minecraftDebug.on("close", (code) => - this.emit("close", "Minecraft closed"), - ); - } - - async DownloadGame() { - const InfoVersion = await new jsonMinecraft(this.options).GetInfoVersion(); - let loaderJson: any = null; - if ("error" in InfoVersion) return this.emit("error", InfoVersion); - - const { json, version } = InfoVersion; - - const libraries = new librariesMinecraft(this.options); - - const bundle = new bundleMinecraft(this.options); - const java = new javaMinecraft(this.options); - - java.on("progress", (progress: any, size: any, element: any) => { - this.emit("progress", progress, size, element); - }); - - java.on("extract", (progress: any) => { - this.emit("extract", progress); - }); - - const gameLibraries: any = await libraries.Getlibraries(json); - const gameAssetsOther: any = await libraries.GetAssetsOthers( - this.options.url, - ); - const gameAssets: any = await new assetsMinecraft(this.options).getAssets( - json, - ); - await new loggingMinecraft(this.options).getLogging(json); - const gameJava: any = this.options.java.path - ? { files: [] } - : await java.getJavaFiles(json); - - if (gameJava.error) return gameJava; - - const filesList: any = await bundle.checkBundle([ - ...gameLibraries, - ...gameAssetsOther, - ...gameAssets, - ...gameJava.files, - ]); - - if (filesList.length > 0) { - let downloader = new Downloader(); - let totsize = await bundle.getTotalSize(filesList); - - downloader.on("progress", (DL: any, totDL: any, element: any) => { - this.emit("progress", DL, totDL, element); - }); - - downloader.on("speed", (speed: any) => { - this.emit("speed", speed); - }); - - downloader.on("estimated", (time: any) => { - this.emit("estimated", time); - }); - - downloader.on("error", (e: any) => { - this.emit("error", e); - }); - - await downloader.downloadFileMultiple( - filesList, - totsize, - this.options.downloadFileMultiple, - this.options.timeout, - ); - } - - if (this.options.loader.enable === true) { - const loaderInstall = new loaderMinecraft(this.options); - - loaderInstall.on("extract", (extract: any) => { - this.emit("extract", extract); - }); - - loaderInstall.on("progress", (progress: any, size: any, element: any) => { - this.emit("progress", progress, size, element); - }); - - loaderInstall.on("check", (progress: any, size: any, element: any) => { - this.emit("check", progress, size, element); - }); - - loaderInstall.on("patch", (patch: any) => { - this.emit("patch", patch); - }); - - const jsonLoader = await loaderInstall - .GetLoader( - version, - this.options.java.path ? this.options.java.path : gameJava.path, - ) - .then((data: any) => data) - .catch((err: any) => err); - if (jsonLoader.error) return jsonLoader; - loaderJson = jsonLoader; - } - - if (this.options.verify) - await bundle.checkFiles([ - ...gameLibraries, - ...gameAssetsOther, - ...gameAssets, - ...gameJava.files, - ]); - - const natives = await libraries.natives(gameLibraries); - if (natives.length === 0) json.nativesList = false; - else json.nativesList = true; - - if (isold(json)) new assetsMinecraft(this.options).copyAssets(json); - - return { - minecraftJson: json, - minecraftLoader: loaderJson, - minecraftVersion: version, - minecraftJava: gameJava, - }; - } -} + options: LaunchOPTS; + + async Launch(opt: LaunchOPTS) { + const defaultOptions: LaunchOPTS = { + url: null, + authenticator: null, + timeout: 10000, + path: '.Minecraft', + version: 'latest_release', + instance: null, + detached: false, + intelEnabledMac: false, + downloadFileMultiple: 5, + bypassOffline: false, + + loader: { + path: './loader', + type: null, + build: 'latest', + enable: false, + }, + + mcp: null, + + verify: false, + ignored: [], + JVM_ARGS: [], + GAME_ARGS: [], + + java: { + path: null, + version: null, + type: 'jre', + }, + + screen: { + width: null, + height: null, + fullscreen: false, + }, + + memory: { + min: '1G', + max: '2G' + }, + ...opt, + }; + + this.options = defaultOptions; + this.options.path = path.resolve(this.options.path).replace(/\\/g, '/'); + + if (this.options.mcp) { + if (this.options.instance) this.options.mcp = `${this.options.path}/instances/${this.options.instance}/${this.options.mcp}` + else this.options.mcp = path.resolve(`${this.options.path}/${this.options.mcp}`).replace(/\\/g, '/') + } + + if (this.options.loader.type) { + this.options.loader.type = this.options.loader.type.toLowerCase() + this.options.loader.build = this.options.loader.build.toLowerCase() + } + + if (!this.options.authenticator) return this.emit("error", { error: "Authenticator not found" }); + if (this.options.downloadFileMultiple < 1) this.options.downloadFileMultiple = 1 + if (this.options.downloadFileMultiple > 30) this.options.downloadFileMultiple = 30 + if (typeof this.options.loader.path !== 'string') this.options.loader.path = `./loader/${this.options.loader.type}`; + if (this.options.java.version && typeof this.options.java.type !== 'string') this.options.java.type = 'jre'; + this.start(); + } + + + async start() { + let data: any = await this.DownloadGame(); + if (data.error) return this.emit('error', data); + let { minecraftJson, minecraftLoader, minecraftVersion, minecraftJava } = data; + + let minecraftArguments: any = await new argumentsMinecraft(this.options).GetArguments(minecraftJson, minecraftLoader); + if (minecraftArguments.error) return this.emit('error', minecraftArguments); + + let loaderArguments: any = await new loaderMinecraft(this.options).GetArguments(minecraftLoader, minecraftVersion); + if (loaderArguments.error) return this.emit('error', loaderArguments); + + let Arguments: any = [ + ...minecraftArguments.jvm, + ...minecraftArguments.classpath, + ...loaderArguments.jvm, + minecraftArguments.mainClass, + ...minecraftArguments.game, + ...loaderArguments.game + ] + + let java: any = this.options.java.path ? this.options.java.path : minecraftJava.path; + let logs = this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path; + if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true }); + + let argumentsLogs: string = Arguments.join(' ') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.access_token, '????????') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.client_token, '????????') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.uuid, '????????') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.xboxAccount?.xuid, '????????') + argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, '') + this.emit('data', `Launching with arguments ${argumentsLogs}`); + + let minecraftDebug = spawn(java, Arguments, { cwd: logs, detached: this.options.detached }) + minecraftDebug.stdout.on('data', (data) => this.emit('data', data.toString('utf-8'))) + minecraftDebug.stderr.on('data', (data) => this.emit('data', data.toString('utf-8'))) + minecraftDebug.on('close', (code) => this.emit('close', 'Minecraft closed')) + } + + async DownloadGame() { + const InfoVersion = await new jsonMinecraft(this.options).GetInfoVersion(); + let loaderJson: any = null; + if ('error' in InfoVersion) return this.emit('error', InfoVersion); + + const { json, version } = InfoVersion; + + const libraries = new librariesMinecraft(this.options) + + const bundle = new bundleMinecraft(this.options) + const java = new javaMinecraft(this.options) + + java.on('progress', (progress: any, size: any, element: any) => { + this.emit('progress', progress, size, element) + }); + + java.on('extract', (progress: any) => { + this.emit('extract', progress) + }); + + const gameLibraries: any = await libraries.Getlibraries(json); + const gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url); + const gameAssets: any = await new assetsMinecraft(this.options).getAssets(json); + await new loggingMinecraft(this.options).getLogging(json); + const gameJava: any = this.options.java.path ? { files: [] } : await java.getJavaFiles(json); + + + if (gameJava.error) return gameJava + + const filesList: any = await bundle.checkBundle([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]); + + if (filesList.length > 0) { + let downloader = new Downloader(); + let totsize = await bundle.getTotalSize(filesList); + + downloader.on("progress", (DL: any, totDL: any, element: any) => { + this.emit("progress", DL, totDL, element); + }); + + downloader.on("speed", (speed: any) => { + this.emit("speed", speed); + }); + + downloader.on("estimated", (time: any) => { + this.emit("estimated", time); + }); + + downloader.on("error", (e: any) => { + this.emit("error", e); + }); + + await downloader.downloadFileMultiple(filesList, totsize, this.options.downloadFileMultiple, this.options.timeout); + } + + if (this.options.loader.enable === true) { + const loaderInstall = new loaderMinecraft(this.options) + + loaderInstall.on('extract', (extract: any) => { + this.emit('extract', extract); + }); + + loaderInstall.on('progress', (progress: any, size: any, element: any) => { + this.emit('progress', progress, size, element); + }); + + loaderInstall.on('check', (progress: any, size: any, element: any) => { + this.emit('check', progress, size, element); + }); + + loaderInstall.on('patch', (patch: any) => { + this.emit('patch', patch); + }); + + const jsonLoader = await loaderInstall.GetLoader(version, this.options.java.path ? this.options.java.path : gameJava.path) + .then((data: any) => data) + .catch((err: any) => err); + if (jsonLoader.error) return jsonLoader; + loaderJson = jsonLoader; + } + + if (this.options.verify) await bundle.checkFiles([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]); + + const natives = await libraries.natives(gameLibraries); + if (natives.length === 0) json.nativesList = false; + else json.nativesList = true; + + if (isold(json)) new assetsMinecraft(this.options).copyAssets(json); + + return { + minecraftJson: json, + minecraftLoader: loaderJson, + minecraftVersion: version, + minecraftJava: gameJava + } + } +} \ No newline at end of file