From 3d5cdf0bff015d9df8af0d66959d4527e9784eb0 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sun, 6 Aug 2023 23:47:47 +0200
Subject: [PATCH 001/185] fix error permes
---
package-lock.json | 14 +-
package.json | 3 +-
src/Launch.ts | 10 +-
src/Minecraft-Loader/index.ts | 144 +++++++++++
src/Minecraft-Loader/loader/fabric/fabric.ts | 94 +++++++
src/Minecraft-Loader/loader/forge/forge.ts | 244 +++++++++++++++++++
src/Minecraft-Loader/loader/forge/patcher.ts | 141 +++++++++++
src/Minecraft-Loader/loader/quilt/quilt.ts | 97 ++++++++
src/Minecraft/Minecraft-Bundle.ts | 82 ++++++-
src/Minecraft/Minecraft-Libraries.ts | 63 -----
src/Minecraft/Minecraft-Loader.ts | 4 +-
src/utils/Downloader.ts | 56 +++++
src/utils/Index.ts | 77 +++++-
test/index.js | 2 +-
14 files changed, 935 insertions(+), 96 deletions(-)
create mode 100644 src/Minecraft-Loader/index.ts
create mode 100644 src/Minecraft-Loader/loader/fabric/fabric.ts
create mode 100644 src/Minecraft-Loader/loader/forge/forge.ts
create mode 100644 src/Minecraft-Loader/loader/forge/patcher.ts
create mode 100644 src/Minecraft-Loader/loader/quilt/quilt.ts
diff --git a/package-lock.json b/package-lock.json
index a7062999..c710d178 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,15 @@
{
"name": "minecraft-java-core",
- "version": "3.5.7",
+ "version": "3.6.0-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.5.7",
+ "version": "3.6.0-beta.1",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
- "minecraft-loader": "^1.3.0",
"node-fetch": "^2.6.9",
"prompt": "^1.2.1",
"tslib": "^2.4.1"
@@ -219,15 +218,6 @@
"node": ">= 0.6"
}
},
- "node_modules/minecraft-loader": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/minecraft-loader/-/minecraft-loader-1.3.0.tgz",
- "integrity": "sha512-r+tXeGBb8CyIVfpLTL1fdG7GQv0yfzygktYk3BVWMYNFLhd3nGBxN/HCR5Lo53iir8m9P/2X9S2jGJ74BDqbHQ==",
- "dependencies": {
- "adm-zip": "^0.5.10",
- "node-fetch": "^2.6.9"
- }
- },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
diff --git a/package.json b/package.json
index a68e30da..fea4beb0 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.5.7",
+ "version": "3.6.0-beta.1",
"types": "./build/Index.d.ts",
"exports": {
".": {
@@ -32,7 +32,6 @@
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
- "minecraft-loader": "^1.3.0",
"node-fetch": "^2.6.9",
"prompt": "^1.2.1",
"tslib": "^2.4.1"
diff --git a/src/Launch.ts b/src/Launch.ts
index 5c4d8848..ac667776 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -114,18 +114,18 @@ export default class Launch {
let { json, version } = InfoVersion;
let libraries = new librariesMinecraft(this.options)
+ let bundle = new bundleMinecraft(this.options)
let gameLibraries: any = await libraries.Getlibraries(json);
let gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url);
let gameAssets: any = await new assetsMinecraft(this.options).GetAssets(json);
let gameJava: any = this.options.javaPath ? { files: [] } : await new javaMinecraft(this.options).GetJsonJava(json);
- let bundle: any = [...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]
- let filesList: any = await new bundleMinecraft(this.options).checkBundle(bundle);
+ let filesList: any = await bundle.checkBundle([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]);
if (filesList.length > 0) {
let downloader = new Downloader();
- let totsize = await new bundleMinecraft(this.options).getTotalSize(filesList);
+ let totsize = await bundle.getTotalSize(filesList);
downloader.on("progress", (DL: any, totDL: any, element: any) => {
this.emit("progress", DL, totDL, element);
@@ -172,9 +172,9 @@ export default class Launch {
loaderJson = jsonLoader;
}
- if (this.options.verify) await libraries.checkFiles(bundle);
+ if (this.options.verify) await bundle.checkFiles([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]);
- let natives = await libraries.natives(bundle);
+ let natives = await libraries.natives(gameLibraries);
if (natives.length === 0) json.nativesList = false;
else json.nativesList = true;
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
new file mode 100644
index 00000000..565b76c3
--- /dev/null
+++ b/src/Minecraft-Loader/index.ts
@@ -0,0 +1,144 @@
+/**
+ * @author Luuxis
+ * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
+ */
+
+import { loader } from '../utils/Index.js';
+import Forge from './loader/forge/forge.js';
+import Fabric from './loader/fabric/fabric.js';
+import Quilt from './loader/quilt/quilt.js';
+
+
+import { EventEmitter } from 'events';
+import fs from 'fs'
+import path from 'path'
+
+export default class Loader {
+ options: any;
+ on: any;
+ emit: any;
+
+ constructor(options) {
+ this.options = options
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async install() {
+ let Loader = loader(this.options.loader.type);
+ if (!Loader) return this.emit('error', { error: `Loader ${this.options.loader.type} not found` });
+
+ if (this.options.loader.type === 'forge') {
+ let forge = await this.forge(Loader);
+ if (forge.error) return this.emit('error', forge);
+ this.emit('json', forge);
+ } else if (this.options.loader.type === 'fabric') {
+ let fabric = await this.fabric(Loader);
+ if (fabric.error) return this.emit('error', fabric);
+ this.emit('json', fabric);
+ } else if (this.options.loader.type === 'quilt') {
+ let quilt = await this.quilt(Loader);
+ if (quilt.error) return this.emit('error', quilt);
+ this.emit('json', quilt);
+ } else {
+ return this.emit('error', { error: `Loader ${this.options.loader.type} not found` });
+ }
+ }
+
+ async forge(Loader: any) {
+ let forge = new Forge(this.options);
+
+ // set event
+ forge.on('check', (progress, size, element) => {
+ this.emit('check', progress, size, element);
+ });
+
+ forge.on('progress', (progress, size, element) => {
+ this.emit('progress', progress, size, element);
+ });
+
+ forge.on('extract', (element) => {
+ this.emit('extract', element);
+ });
+
+ forge.on('patch', patch => {
+ this.emit('patch', patch);
+ });
+
+ // download installer
+ let installer = await forge.donwloadInstaller(Loader);
+ if (installer.error) return installer;
+
+ // extract install profile
+ let profile: any = await forge.extractProfile(installer.filePath);
+ if (profile.error) return profile
+ let destination = path.resolve(this.options.path, 'versions', profile.version.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
+
+ // extract universal jar
+ let universal: any = await forge.extractUniversalJar(profile.install, installer.filePath);
+ if (universal.error) return universal;
+
+ // download libraries
+ let libraries: any = await forge.downloadLibraries(profile, universal);
+ if (libraries.error) return libraries;
+
+ // patch forge if nessary
+ let patch: any = await forge.patchForge(profile.install);
+ if (patch.error) return patch;
+
+ return profile.version;
+ }
+
+ async fabric(Loader: any) {
+ let fabric = new Fabric(this.options);
+
+ // set event
+ fabric.on('check', (progress, size, element) => {
+ this.emit('check', progress, size, element);
+ });
+
+ fabric.on('progress', (progress, size, element) => {
+ this.emit('progress', progress, size, element);
+ });
+
+ // download Json
+ let json = await fabric.downloadJson(Loader);
+ if (json.error) return json;
+ let destination = path.resolve(this.options.path, 'versions', json.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${json.id}.json`), JSON.stringify(json, null, 4));
+
+ // download libraries
+ await fabric.downloadLibraries(json);
+
+ return json;
+ }
+
+ async quilt(Loader: any) {
+ let quilt = new Quilt(this.options);
+
+ // set event
+ quilt.on('check', (progress, size, element) => {
+ this.emit('check', progress, size, element);
+ });
+
+ quilt.on('progress', (progress, size, element) => {
+ this.emit('progress', progress, size, element);
+ });
+
+ // download Json
+ let json = await quilt.downloadJson(Loader);
+
+ if (json.error) return json;
+ let destination = path.resolve(this.options.path, 'versions', json.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${json.id}.json`), JSON.stringify(json, null, 4));
+
+ // // download libraries
+ await quilt.downloadLibraries(json);
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/Minecraft-Loader/loader/fabric/fabric.ts b/src/Minecraft-Loader/loader/fabric/fabric.ts
new file mode 100644
index 00000000..a7e9eb14
--- /dev/null
+++ b/src/Minecraft-Loader/loader/fabric/fabric.ts
@@ -0,0 +1,94 @@
+/**
+ * @author Luuxis
+ * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
+ */
+
+import { getPathLibraries } from '../../../utils/Index.js';
+import download from '../../../utils/Downloader.js';
+
+import nodeFetch from 'node-fetch'
+import fs from 'fs'
+import path from'path'
+import { EventEmitter } from 'events';
+
+export default class FabricMC {
+ options: any;
+ on: any;
+ emit: any;
+
+ constructor(options = {}) {
+ this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async downloadJson(Loader) {
+ let build
+ let metaData = await nodeFetch(Loader.metaData).then(res => res.json());
+
+ let version = metaData.game.find(version => version.version === this.options.loader.version);
+ let AvailableBuilds = metaData.loader.map(build => build.version);
+ if (!version) return { error: `FabricMC doesn't support Minecraft ${this.options.loader.version}` };
+
+ if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') {
+ build = metaData.loader[0];
+ } else {
+ build = metaData.loader.find(loader => loader.version === this.options.loader.build);
+ }
+
+ if (!build) return { error: `Fabric Loader ${this.options.loader.build} not fond, Available builds: ${AvailableBuilds.join(', ')}` };
+
+ let url = Loader.json.replace('${build}', build.version).replace('${version}', this.options.loader.version);
+ let json = await nodeFetch(url).then(res => res.json()).catch(err => err);
+ return json
+ }
+
+ async downloadLibraries(json) {
+ let { libraries } = json;
+ let downloader = new download();
+ let files:any = [];
+ let check = 0;
+ let size = 0;
+
+ for (let lib of libraries) {
+ if (lib.rules) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ let file = {}
+ let libInfo = getPathLibraries(lib.name);
+ let pathLib = path.resolve(this.options.path, 'libraries', libInfo.path);
+ let pathLibFile = path.resolve(pathLib, libInfo.name);
+
+ if (!fs.existsSync(pathLibFile)) {
+ let url = `${lib.url}${libInfo.path}/${libInfo.name}`
+ let sizeFile = 0
+
+ let res:any = await downloader.checkURL(url);
+ if (res.status === 200) {
+ sizeFile = res.size;
+ size += res.size;
+ }
+
+ file = {
+ url: url,
+ folder: pathLib,
+ path: `${pathLib}/${libInfo.name}`,
+ name: libInfo.name,
+ size: sizeFile
+ }
+ files.push(file);
+ }
+ this.emit('check', check++, libraries.length, 'libraries');
+ }
+
+ if (files.length > 0) {
+ downloader.on("progress", (DL, totDL) => {
+ this.emit("progress", DL, totDL, 'libraries');
+ });
+
+ await downloader.downloadFileMultiple(files, size, this.options.downloadFileMultiple);
+ }
+ return libraries
+ }
+}
\ No newline at end of file
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
new file mode 100644
index 00000000..ea332b28
--- /dev/null
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -0,0 +1,244 @@
+/**
+ * @author Luuxis
+ * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
+ */
+
+import { getPathLibraries, getFileHash, mirrors, getFileFromJar } from '../../../utils/Index.js';
+import download from '../../../utils/Downloader.js';
+import forgePatcher from './patcher.js'
+
+import nodeFetch from 'node-fetch'
+import fs from 'fs'
+import path from 'path'
+import { EventEmitter } from 'events';
+
+export default class ForgeMC {
+ options: any;
+ on: any;
+ emit: any;
+
+ constructor(options = {}) {
+ this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async donwloadInstaller(Loader: any) {
+ let metaData = (await nodeFetch(Loader.metaData).then(res => res.json()))[this.options.loader.version];
+ let AvailableBuilds = metaData;
+ let forgeURL = Loader.install
+ if (!metaData) return { error: `Forge ${this.options.loader.version} not supported` };
+
+ let build
+ if (this.options.loader.build === 'latest') {
+ let promotions = await nodeFetch(Loader.promotions).then(res => res.json());
+ promotions = promotions.promos[`${this.options.loader.version}-latest`];
+ build = metaData.find(build => build.includes(promotions))
+ } else if (this.options.loader.build === 'recommended') {
+ let promotion = await nodeFetch(Loader.promotions).then(res => res.json());
+ let promotions = promotion.promos[`${this.options.loader.version}-recommended`];
+ if (!promotions) promotions = promotion.promos[`${this.options.loader.version}-latest`];
+ build = metaData.find(build => build.includes(promotions))
+ } else {
+ build = this.options.loader.build;
+ }
+
+ metaData = metaData.filter(b => b === build)[0];
+ if (!metaData) return { error: `Build ${build} not found, Available builds: ${AvailableBuilds.join(', ')}` };
+
+ forgeURL = forgeURL.replace(/\${version}/g, metaData);
+ let urlMeta = Loader.meta.replace(/\${build}/g, metaData);
+
+ let pathFolder = path.resolve(this.options.path, 'forge');
+ let filePath = path.resolve(pathFolder, `forge-${metaData}-installer.jar`);
+ let meta = await nodeFetch(urlMeta).then(res => res.json());
+
+ if (!fs.existsSync(filePath)) {
+ if (!fs.existsSync(pathFolder)) fs.mkdirSync(pathFolder, { recursive: true });
+ let downloadForge = new download();
+
+ downloadForge.on('progress', (downloaded, size) => {
+ this.emit('progress', downloaded, size, `forge-${metaData}-installer.jar`);
+ });
+
+ await downloadForge.downloadFile(forgeURL, pathFolder, `forge-${metaData}-installer.jar`);
+ }
+
+ let hashFileDownload = await getFileHash(filePath, 'md5');
+ let hashFileOrigin = meta?.classifiers?.installer?.jar;
+
+ if (hashFileDownload !== hashFileOrigin) {
+ fs.rmSync(filePath);
+ return { error: 'Invalid hash' };
+ }
+ return { filePath, metaData }
+ }
+
+ async extractProfile(pathInstaller: any) {
+ let forgeJSON: any = {}
+
+ let file: any = await getFileFromJar(pathInstaller, 'install_profile.json')
+ let forgeJsonOrigin = JSON.parse(file);
+
+ if (!forgeJsonOrigin) return { error: { message: 'Invalid forge installer' } };
+ if (forgeJsonOrigin.install) {
+ forgeJSON.install = forgeJsonOrigin.install;
+ forgeJSON.version = forgeJsonOrigin.versionInfo;
+ } else {
+ forgeJSON.install = forgeJsonOrigin;
+ let file: any = await getFileFromJar(pathInstaller, path.basename(forgeJSON.install.json))
+ forgeJSON.version = JSON.parse(file);
+ }
+
+ return forgeJSON;
+ }
+
+ async extractUniversalJar(profile: any, pathInstaller: any) {
+ let skipForgeFilter = true
+
+ if (profile.filePath) {
+ let fileInfo = getPathLibraries(profile.path)
+ this.emit('extract', `Extracting ${fileInfo.name}...`);
+
+ let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
+ if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
+
+ let file: any = await getFileFromJar(pathInstaller, profile.filePath)
+ fs.writeFileSync(`${pathFileDest}/${fileInfo.name}`, file, { mode: 0o777 })
+ } else if (profile.path) {
+ let fileInfo = getPathLibraries(profile.path)
+ let listFile: any = await getFileFromJar(pathInstaller, null, `maven/${fileInfo.path}`)
+
+ await Promise.all(
+ listFile.map(async (files: any) => {
+ let fileName = files.split('/')
+ this.emit('extract', `Extracting ${fileName[fileName.length - 1]}...`);
+ let file: any = await getFileFromJar(pathInstaller, files)
+ let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
+ if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
+ fs.writeFileSync(`${pathFileDest}/${fileName[fileName.length - 1]}`, file, { mode: 0o777 })
+ })
+ );
+ } else {
+ skipForgeFilter = false
+ }
+
+ if (profile.processors?.length) {
+ let universalPath = profile.libraries.find(v => {
+ return (v.name || '').startsWith('net.minecraftforge:forge')
+ })
+
+ let client: any = await getFileFromJar(pathInstaller, 'data/client.lzma');
+ let fileInfo = getPathLibraries(profile.path || universalPath.name, '-clientdata', '.lzma')
+ let pathFile = path.resolve(this.options.path, 'libraries', fileInfo.path)
+
+ if (!fs.existsSync(pathFile)) fs.mkdirSync(pathFile, { recursive: true });
+ fs.writeFileSync(`${pathFile}/${fileInfo.name}`, client, { mode: 0o777 })
+ this.emit('extract', `Extracting ${fileInfo.name}...`);
+ }
+
+ return skipForgeFilter
+ }
+
+ async downloadLibraries(profile: any, skipForgeFilter: any) {
+ let { libraries } = profile.version;
+ let downloader = new download();
+ let check = 0;
+ let files: any = [];
+ let size = 0;
+
+ if (profile.install.libraries) libraries = libraries.concat(profile.install.libraries);
+
+ libraries = libraries.filter((library, index, self) => index === self.findIndex(t => t.name === library.name))
+
+ let skipForge = [
+ 'net.minecraftforge:forge:',
+ 'net.minecraftforge:minecraftforge:'
+ ]
+
+ for (let lib of libraries) {
+ if (skipForgeFilter && skipForge.find(libs => lib.name.includes(libs))) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ if (lib.rules) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ let file = {}
+ let libInfo = getPathLibraries(lib.name);
+ let pathLib = path.resolve(this.options.path, 'libraries', libInfo.path);
+ let pathLibFile = path.resolve(pathLib, libInfo.name);
+
+ if (!fs.existsSync(pathLibFile)) {
+ let url
+ let sizeFile = 0
+
+ let baseURL = `${libInfo.path}/${libInfo.name}`;
+ let response: any = await downloader.checkMirror(baseURL, mirrors)
+
+ if (response?.status === 200) {
+ size += response.size;
+ sizeFile = response.size;
+ url = response.url;
+ } else if (lib.downloads?.artifact) {
+ url = lib.downloads.artifact.url
+ size += lib.downloads.artifact.size;
+ sizeFile = lib.downloads.artifact.size;
+ } else {
+ url = null
+ }
+
+ if (url == null || !url) {
+ return { error: `Impossible to download ${libInfo.name}` };
+ }
+
+ file = {
+ url: url,
+ folder: pathLib,
+ path: `${pathLib}/${libInfo.name}`,
+ name: libInfo.name,
+ size: sizeFile
+ }
+ files.push(file);
+ }
+ this.emit('check', check++, libraries.length, 'libraries');
+ }
+
+ if (files.length > 0) {
+ downloader.on("progress", (DL, totDL) => {
+ this.emit("progress", DL, totDL, 'libraries');
+ });
+
+ await downloader.downloadFileMultiple(files, size, this.options.downloadFileMultiple);
+ }
+ return libraries
+ }
+
+ async patchForge(profile: any) {
+ if (profile?.processors?.length) {
+ let patcher: any = new forgePatcher(this.options);
+ let config: any = {}
+
+ patcher.on('patch', data => {
+ this.emit('patch', data);
+ });
+
+ patcher.on('error', data => {
+ this.emit('error', data);
+ });
+
+ if (!patcher.check(profile)) {
+ config = {
+ java: this.options.loader.config.javaPath,
+ minecraft: this.options.loader.config.minecraftJar,
+ minecraftJson: this.options.loader.config.minecraftJson
+ }
+
+ await patcher.patcher(profile, config);
+ }
+ }
+
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/Minecraft-Loader/loader/forge/patcher.ts b/src/Minecraft-Loader/loader/forge/patcher.ts
new file mode 100644
index 00000000..8c46214c
--- /dev/null
+++ b/src/Minecraft-Loader/loader/forge/patcher.ts
@@ -0,0 +1,141 @@
+import { spawn } from 'child_process';
+import fs from 'fs'
+import path from 'path'
+import { EventEmitter } from 'events';
+
+import { getPathLibraries, getFileFromJar } from '../../../utils/Index.js';
+
+
+
+export default class forgePatcher {
+ options: any;
+ on: any;
+ emit: any;
+
+ constructor(options: any) {
+ this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async patcher(profile: any, config: any) {
+ let { processors } = profile;
+
+ for (let key in processors) {
+ if (Object.prototype.hasOwnProperty.call(processors, key)) {
+ let processor = processors[key];
+ if (processor?.sides && !(processor?.sides || []).includes('client')) {
+ continue;
+ }
+
+ let jar = getPathLibraries(processor.jar)
+ let filePath = path.resolve(this.options.path, 'libraries', jar.path, jar.name)
+
+ let args = processor.args.map(arg => this.setArgument(arg, profile, config)).map(arg => this.computePath(arg));
+ let classPaths = processor.classpath.map(cp => {
+ let classPath = getPathLibraries(cp)
+ return `"${path.join(this.options.path, 'libraries', `${classPath.path}/${classPath.name}`)}"`
+ });
+ let mainClass = await this.readJarManifest(filePath);
+
+ await new Promise((resolve: any) => {
+ const ps = spawn(
+ `"${path.resolve(config.java)}"`,
+ [
+ '-classpath',
+ [`"${filePath}"`, ...classPaths].join(path.delimiter),
+ mainClass,
+ ...args
+ ], { shell: true }
+ );
+
+ ps.stdout.on('data', data => {
+ this.emit('patch', data.toString('utf-8'))
+ });
+
+ ps.stderr.on('data', data => {
+ this.emit('patch', data.toString('utf-8'))
+ });
+
+ ps.on('close', code => {
+ if (code !== 0) {
+ this.emit('error', `Forge patcher exited with code ${code}`);
+ resolve();
+ }
+ resolve();
+ });
+ });
+ }
+ }
+
+ }
+
+ check(profile: any) {
+ let files = [];
+ let { processors } = profile;
+
+ for (let key in processors) {
+ if (Object.prototype.hasOwnProperty.call(processors, key)) {
+ let processor = processors[key];
+ if (processor?.sides && !(processor?.sides || []).includes('client')) continue;
+
+ processor.args.map(arg => {
+ let finalArg = arg.replace('{', '').replace('}', '');
+ if (profile.data[finalArg]) {
+ if (finalArg === 'BINPATCH') return
+ files.push(profile.data[finalArg].client)
+ }
+ })
+ }
+ }
+
+ files = files.filter((item, index) => files.indexOf(item) === index);
+
+ for (let file of files) {
+ let libMCP = getPathLibraries(file.replace('[', '').replace(']', ''))
+ file = `${path.resolve(this.options.path, 'libraries', `${libMCP.path}/${libMCP.name}`)}`;
+ if (!fs.existsSync(file)) return false
+ }
+ return true;
+ }
+
+ setArgument(arg: any, profile: any, config: any) {
+ let finalArg = arg.replace('{', '').replace('}', '');
+ let universalPath = profile.libraries.find(v =>
+ (v.name || '').startsWith('net.minecraftforge:forge')
+ )
+
+ if (profile.data[finalArg]) {
+ if (finalArg === 'BINPATCH') {
+ let clientdata = getPathLibraries(profile.path || universalPath.name)
+ return `"${path
+ .join(this.options.path, 'libraries', `${clientdata.path}/${clientdata.name}`)
+ .replace('.jar', '-clientdata.lzma')}"`;
+ }
+ return profile.data[finalArg].client;
+ }
+
+ return arg
+ .replace('{SIDE}', `client`)
+ .replace('{ROOT}', `"${path.dirname(path.resolve(this.options.path, 'forge'))}"`)
+ .replace('{MINECRAFT_JAR}', `"${config.minecraft}"`)
+ .replace('{MINECRAFT_VERSION}', `"${config.minecraftJson}"`)
+ .replace('{INSTALLER}', `"${this.options.path}/libraries"`)
+ .replace('{LIBRARY_DIR}', `"${this.options.path}/libraries"`);
+ }
+
+ computePath(arg: any) {
+ if (arg[0] === '[') {
+ let libMCP = getPathLibraries(arg.replace('[', '').replace(']', ''))
+ return `"${path.join(this.options.path, 'libraries', `${libMCP.path}/${libMCP.name}`)}"`;
+ }
+ return arg;
+ }
+
+ async readJarManifest(jarPath: string) {
+ let extraction: any = await getFileFromJar(jarPath, 'META-INF/MANIFEST.MF');
+
+ if (extraction) return (extraction.toString("utf8")).split('Main-Class: ')[1].split('\r\n')[0];
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/Minecraft-Loader/loader/quilt/quilt.ts b/src/Minecraft-Loader/loader/quilt/quilt.ts
new file mode 100644
index 00000000..1e6f550a
--- /dev/null
+++ b/src/Minecraft-Loader/loader/quilt/quilt.ts
@@ -0,0 +1,97 @@
+/**
+ * @author Luuxis
+ * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
+ */
+
+import { getPathLibraries } from '../../../utils/Index.js';
+import download from '../../../utils/Downloader.js';
+
+import nodeFetch from 'node-fetch'
+import fs from 'fs'
+import path from 'path'
+import { EventEmitter } from 'events';
+
+export default class Quilt {
+ options: any;
+ versionMinecraft: any;
+ on: any;
+ emit: any;
+
+ constructor(options = {}) {
+ this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async downloadJson(Loader: any) {
+ let build: any
+ let metaData = await nodeFetch(Loader.metaData).then(res => res.json());
+
+ let version = metaData.game.find(version => version.version === this.options.loader.version);
+ let AvailableBuilds = metaData.loader.map(build => build.version);
+ if (!version) return { error: `QuiltMC doesn't support Minecraft ${this.options.loader.version}` };
+
+ if (this.options.loader.build === 'latest') {
+ build = metaData.loader[0];
+ } else if (this.options.loader.build === 'recommended') {
+ build = metaData.loader.find(build => !build.version.includes('beta'));
+ } else {
+ build = metaData.loader.find(loader => loader.version === this.options.loader.build);
+ }
+
+ if (!build) return { error: `QuiltMC Loader ${this.options.loader.build} not fond, Available builds: ${AvailableBuilds.join(', ')}` };
+
+ let url = Loader.json.replace('${build}', build.version).replace('${version}', this.options.loader.version);
+ let json = await nodeFetch(url).then(res => res.json()).catch(err => err);
+ return json
+ }
+
+ async downloadLibraries(json) {
+ let { libraries } = json;
+ let downloader = new download();
+ let files: any = [];
+ let check = 0;
+ let size = 0;
+
+ for (let lib of libraries) {
+ if (lib.rules) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ let file = {}
+ let libInfo = getPathLibraries(lib.name);
+ let pathLib = path.resolve(this.options.path, 'libraries', libInfo.path);
+ let pathLibFile = path.resolve(pathLib, libInfo.name);
+
+ if (!fs.existsSync(pathLibFile)) {
+ let url = `${lib.url}${libInfo.path}/${libInfo.name}`
+ let sizeFile = 0
+
+ let res: any = await downloader.checkURL(url);
+ if (res.status === 200) {
+ sizeFile = res.size;
+ size += res.size;
+ }
+
+ file = {
+ url: url,
+ folder: pathLib,
+ path: `${pathLib}/${libInfo.name}`,
+ name: libInfo.name,
+ size: sizeFile
+ }
+ files.push(file);
+ }
+ this.emit('check', check++, libraries.length, 'libraries');
+ }
+
+ if (files.length > 0) {
+ downloader.on("progress", (DL: any, totDL: any) => {
+ this.emit("progress", DL, totDL, 'libraries');
+ });
+
+ await downloader.downloadFileMultiple(files, size, this.options.downloadFileMultiple);
+ }
+ return libraries
+ }
+}
\ No newline at end of file
diff --git a/src/Minecraft/Minecraft-Bundle.ts b/src/Minecraft/Minecraft-Bundle.ts
index ad047eb3..8e032680 100755
--- a/src/Minecraft/Minecraft-Bundle.ts
+++ b/src/Minecraft/Minecraft-Bundle.ts
@@ -5,7 +5,7 @@
import fs from 'fs';
import path from 'path';
-import crypto from 'crypto';
+import { getFileHash } from '../utils/Index.js'
export default class MinecraftBundle {
options: any;
@@ -29,18 +29,19 @@ export default class MinecraftBundle {
if (fs.existsSync(file.path)) {
if (this.options.ignored.find(ignored => ignored == file.path.split("/").slice(-1)[0])) continue
- if (file.sha1) if (!(await this.checkSHA1(file.path, file.sha1))) todownload.push(file);
- } else todownload.push(file);
+ if (file.sha1) {
+ if (await getFileHash(file.path) != file.sha1) {
+ todownload.push(file);
+ }
+ }
+
+ } else {
+ todownload.push(file);
+ }
}
return todownload;
}
- async checkSHA1(file: string, sha1: string) {
- const hex = crypto.createHash('sha1').update(fs.readFileSync(file)).digest('hex')
- if (hex == sha1) return true;
- return false;
- }
-
async getTotalSize(bundle: any) {
let todownload = 0;
for (let file of bundle) {
@@ -48,4 +49,67 @@ export default class MinecraftBundle {
}
return todownload;
}
+
+ async checkFiles(bundle: any) {
+ let instancePath = ''
+ let instanceFolder = []
+ if (this.options.instance) {
+ if (!fs.existsSync(`${this.options.path}/instances`)) fs.mkdirSync(`${this.options.path}/instances`, { recursive: true });
+ instancePath = `/instances/${this.options.instance}`
+ instanceFolder = fs.readdirSync(`${this.options.path}/instances`).filter(dir => dir != this.options.instance)
+ }
+ let files = this.getFiles(this.options.path);
+ let ignoredfiles = [...this.getFiles(`${this.options.path}/loader`)]
+
+ for (let instances of instanceFolder) {
+ ignoredfiles.push(...this.getFiles(`${this.options.path}/instances/${instances}`));
+ }
+
+ for (let file of this.options.ignored) {
+ file = (`${this.options.path}${instancePath}/${file}`)
+ if (fs.existsSync(file)) {
+ if (fs.statSync(file).isDirectory()) {
+ ignoredfiles.push(...this.getFiles(file));
+ } else if (fs.statSync(file).isFile()) {
+ ignoredfiles.push(file);
+ }
+ }
+ }
+
+ ignoredfiles.forEach(file => this.options.ignored.push((file)));
+ bundle.forEach(file => ignoredfiles.push((file.path)));
+ files = files.filter(file => ignoredfiles.indexOf(file) < 0);
+
+ for (let file of files) {
+ try {
+ if (fs.statSync(file).isDirectory()) {
+ fs.rmdirSync(file);
+ } else {
+ fs.unlinkSync(file);
+ let folder = file.split("/").slice(0, -1).join("/");
+ while (true) {
+ if (folder == this.options.path) break;
+ let content = fs.readdirSync(folder);
+ if (content.length == 0) fs.rmdirSync(folder);
+ folder = folder.split("/").slice(0, -1).join("/");
+ }
+ }
+ } catch (e) {
+ continue;
+ }
+ }
+ }
+
+ getFiles(path: any, file = []) {
+ if (fs.existsSync(path)) {
+ let files = fs.readdirSync(path);
+ if (files.length == 0) file.push(path);
+ for (let i in files) {
+ let name = `${path}/${files[i]}`;
+ if (fs.statSync(name).isDirectory()) this.getFiles(name, file);
+ else file.push(name);
+ }
+ }
+ return file;
+ }
}
\ No newline at end of file
diff --git a/src/Minecraft/Minecraft-Libraries.ts b/src/Minecraft/Minecraft-Libraries.ts
index 5ca38b0f..2576ca8a 100755
--- a/src/Minecraft/Minecraft-Libraries.ts
+++ b/src/Minecraft/Minecraft-Libraries.ts
@@ -105,67 +105,4 @@ export default class Libraries {
}
return natives;
}
-
- async checkFiles(bundle: any) {
- let instancePath = ''
- let instanceFolder = []
- if (this.options.instance) {
- if (!fs.existsSync(`${this.options.path}/instances`)) fs.mkdirSync(`${this.options.path}/instances`, { recursive: true });
- instancePath = `/instances/${this.options.instance}`
- instanceFolder = fs.readdirSync(`${this.options.path}/instances`).filter(dir => dir != this.options.instance)
- }
- let files = this.getFiles(this.options.path);
- let ignoredfiles = [...this.getFiles(`${this.options.path}/loader`)]
-
- for (let instances of instanceFolder) {
- ignoredfiles.push(...this.getFiles(`${this.options.path}/instances/${instances}`));
- }
-
- for (let file of this.options.ignored) {
- file = (`${this.options.path}${instancePath}/${file}`)
- if (fs.existsSync(file)) {
- if (fs.statSync(file).isDirectory()) {
- ignoredfiles.push(...this.getFiles(file));
- } else if (fs.statSync(file).isFile()) {
- ignoredfiles.push(file);
- }
- }
- }
-
- ignoredfiles.forEach(file => this.options.ignored.push((file)));
- bundle.forEach(file => ignoredfiles.push((file.path)));
- files = files.filter(file => ignoredfiles.indexOf(file) < 0);
-
- for (let file of files) {
- try {
- if (fs.statSync(file).isDirectory()) {
- fs.rmdirSync(file);
- } else {
- fs.unlinkSync(file);
- let folder = file.split("/").slice(0, -1).join("/");
- while (true) {
- if (folder == this.options.path) break;
- let content = fs.readdirSync(folder);
- if (content.length == 0) fs.rmdirSync(folder);
- folder = folder.split("/").slice(0, -1).join("/");
- }
- }
- } catch (e) {
- continue;
- }
- }
- }
-
- getFiles(path: any, file = []) {
- if (fs.existsSync(path)) {
- let files = fs.readdirSync(path);
- if (files.length == 0) file.push(path);
- for (let i in files) {
- let name = `${path}/${files[i]}`;
- if (fs.statSync(name).isDirectory()) this.getFiles(name, file);
- else file.push(name);
- }
- }
- return file;
- }
}
\ No newline at end of file
diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts
index 4141872c..1f60f107 100755
--- a/src/Minecraft/Minecraft-Loader.ts
+++ b/src/Minecraft/Minecraft-Loader.ts
@@ -4,7 +4,7 @@
*/
import { EventEmitter } from 'events';
-const loaderDownloader = require('minecraft-loader');
+import loaderDownloader from '../Minecraft-Loader/index.js'
export default class MinecraftLoader {
@@ -20,9 +20,7 @@ export default class MinecraftLoader {
async GetLoader(version: any, javaPath: any) {
let loader = new loaderDownloader({
path: `${this.options.path}/loader/${this.options.loader.type}`,
- timeout: this.options.timeout,
downloadFileMultiple: this.options.downloadFileMultiple,
- autoClean: true,
loader: {
type: this.options.loader.type,
version: version,
diff --git a/src/utils/Downloader.ts b/src/utils/Downloader.ts
index 0f352fe1..660dfc23 100755
--- a/src/utils/Downloader.ts
+++ b/src/utils/Downloader.ts
@@ -23,6 +23,31 @@ export default class download {
this.emit = EventEmitter.prototype.emit;
}
+ async downloadFile(url: string, path: string, fileName: string) {
+ if (!fs.existsSync(path)) fs.mkdirSync(path, { recursive: true });
+ const writer = fs.createWriteStream(path + '/' + fileName);
+ const response = await nodeFetch(url);
+ const size = response.headers.get('content-length');
+ let downloaded = 0;
+ return new Promise((resolve: any, reject: any) => {
+ response.body.on('data', (chunk) => {
+ downloaded += chunk.length;
+ this.emit('progress', downloaded, size);
+ writer.write(chunk);
+ });
+
+ response.body.on('end', () => {
+ writer.end();
+ resolve();
+ });
+
+ response.body.on('error', (err) => {
+ this.emit('error', err);
+ reject(err);
+ });
+ })
+ }
+
async downloadFileMultiple(files: downloadOptions, size: number, limit: number = 1, timeout: number = 10000) {
if (limit > files.length) limit = files.length;
let completed = 0;
@@ -92,4 +117,35 @@ export default class download {
}, 100);
});
}
+
+ async checkURL(url: string, timeout = 10000) {
+ return await new Promise(async (resolve, reject) => {
+ await nodeFetch(url, { method: 'HEAD', timeout: timeout }).then(res => {
+ if (res.status === 200) {
+ resolve({
+ size: parseInt(res.headers.get('content-length')),
+ status: res.status
+ })
+ }
+ })
+ reject(false);
+ });
+ }
+
+ async checkMirror(baseURL: string, mirrors: any) {
+ for (let mirror of mirrors) {
+ let url = `${mirror}/${baseURL}`;
+ let res: any = await this.checkURL(url).then(res => res).catch(err => false);
+
+ if (res?.status == 200) {
+ return {
+ url: url,
+ size: res.size,
+ status: res.status
+ }
+ break;
+ } continue;
+ }
+ return false;
+ }
}
\ No newline at end of file
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index aa299dc2..9fc4eb4d 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -3,6 +3,10 @@
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
+import crypto from 'crypto';
+import fs from 'fs';
+import admZip from 'adm-zip';
+
function getPathLibraries(main: any, nativeString?: any, forceExt?: any) {
let libSplit = main.split(':')
let fileName = libSplit[3] ? `${libSplit[2]}-${libSplit[3]}` : libSplit[2];
@@ -14,8 +18,79 @@ function getPathLibraries(main: any, nativeString?: any, forceExt?: any) {
};
}
+async function getFileHash(filePath: string, algorithm: string = 'sha1') {
+ let shasum = crypto.createHash(algorithm);
+
+ let file = fs.createReadStream(filePath);
+ file.on('data', data => {
+ shasum.update(data);
+ });
+
+ let hash = await new Promise(resolve => {
+ file.on('end', () => {
+ resolve(shasum.digest('hex'));
+ });
+ });
+ return hash;
+}
+
function isold(json: any) {
return json.assets === 'legacy' || json.assets === 'pre-1.6'
}
-export { getPathLibraries, isold };
\ No newline at end of file
+function loader(type: string) {
+ if (type === 'forge') {
+ return {
+ metaData: 'https://files.minecraftforge.net/net/minecraftforge/forge/maven-metadata.json',
+ meta: 'https://files.minecraftforge.net/net/minecraftforge/forge/${build}/meta.json',
+ promotions: 'https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json',
+ install: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-installer.jar'
+
+ }
+ } else if (type === 'fabric') {
+ return {
+ metaData: 'https://meta.fabricmc.net/v2/versions',
+ json: 'https://meta.fabricmc.net/v2/versions/loader/${version}/${build}/profile/json'
+ }
+ } else if (type === 'quilt') {
+ return {
+ metaData: 'https://meta.quiltmc.org/v3/versions',
+ json: 'https://meta.quiltmc.org/v3/versions/loader/${version}/${build}/profile/json'
+ }
+ }
+}
+
+
+let mirrors = [
+ "https://maven.minecraftforge.net",
+ "https://maven.creeperhost.net",
+ "https://libraries.minecraft.net"
+]
+
+async function getFileFromJar(jar: string, file: string = null, path: string = null) {
+ let fileReturn: any = []
+ let zip = new admZip(jar);
+ let entries = zip.getEntries();
+
+ return new Promise(resolve => {
+ for (let entry of entries) {
+ if (!entry.isDirectory && !path) {
+ if (entry.entryName == file) fileReturn = entry.getData();
+ }
+
+ if (!entry.isDirectory && entry.entryName.includes(path)) {
+ fileReturn.push(entry.entryName)
+ }
+ }
+ resolve(fileReturn);
+ });
+}
+
+export {
+ getPathLibraries,
+ isold,
+ getFileHash,
+ mirrors,
+ loader,
+ getFileFromJar
+};
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 84e123f6..fcc32820 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,7 +27,7 @@ let mc
timeout: 10000,
path: './.Minecraft',
instance: 'Hypixel',
- version: '1.20.1',
+ version: '1.16.5',
detached: false,
downloadFileMultiple: 30,
From 9ac59d9cecc3e622eb94a88e72bebc922e7b8f19 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 9 Aug 2023 17:54:05 +0200
Subject: [PATCH 002/185] Update index.js
---
test/index.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/index.js b/test/index.js
index fcc32820..91e077d3 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,13 +27,13 @@ let mc
timeout: 10000,
path: './.Minecraft',
instance: 'Hypixel',
- version: '1.16.5',
+ version: '1.20.1',
detached: false,
downloadFileMultiple: 30,
loader: {
- type: 'forge',
- build: 'latest',
+ type: 'fabric',
+ build: '0.14.22',
enable: true
},
From 44a5addcb4b13bae248f8eaed8e05bbe53ffe725 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 12 Aug 2023 18:50:31 +0200
Subject: [PATCH 003/185] add support neo-forge
---
package-lock.json | 4 +-
package.json | 2 +-
src/Launch.ts | 11 +-
src/Minecraft-Loader/index.ts | 57 ++++-
src/Minecraft-Loader/loader/fabric/fabric.ts | 2 +-
src/Minecraft-Loader/loader/forge/forge.ts | 4 +-
.../loader/neoForge/neoForge.ts | 226 ++++++++++++++++++
src/Minecraft-Loader/loader/quilt/quilt.ts | 2 +-
.../{loader/forge => }/patcher.ts | 9 +-
src/Minecraft/Minecraft-Arguments.ts | 17 +-
src/Minecraft/Minecraft-Loader.ts | 2 +-
src/utils/Index.ts | 7 +-
test/3D/index.html | 14 --
test/3D/index.js | 24 --
test/index.js | 27 ++-
tsconfig.json | 6 +-
16 files changed, 344 insertions(+), 70 deletions(-)
create mode 100644 src/Minecraft-Loader/loader/neoForge/neoForge.ts
rename src/Minecraft-Loader/{loader/forge => }/patcher.ts (93%)
delete mode 100755 test/3D/index.html
delete mode 100755 test/3D/index.js
diff --git a/package-lock.json b/package-lock.json
index c710d178..11301c28 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.6.0-beta.1",
+ "version": "3.6.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.6.0-beta.1",
+ "version": "3.6.0",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index fea4beb0..7240516a 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.6.0-beta.1",
+ "version": "3.6.0",
"types": "./build/Index.d.ts",
"exports": {
".": {
diff --git a/src/Launch.ts b/src/Launch.ts
index ac667776..3a2f2f06 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -45,8 +45,8 @@ export default class Launch {
downloadFileMultiple: opt?.downloadFileMultiple || 3,
loader: {
- type: opt?.loader?.type || null,
- build: opt?.loader?.build || 'latest',
+ type: opt?.loader?.type?.toLowerCase() || null,
+ build: opt?.loader?.build?.toLowerCase() || 'latest',
enable: opt?.loader?.enable || false,
},
@@ -89,10 +89,11 @@ export default class Launch {
let Arguments: any = [
...minecraftArguments.jvm,
- ...loaderArguments.jvm,
...minecraftArguments.classpath,
- ...loaderArguments.game,
- ...minecraftArguments.game
+ ...loaderArguments.jvm,
+ minecraftArguments.mainClass,
+ ...minecraftArguments.game,
+ ...loaderArguments.game
]
let java: any = this.options.javaPath ? this.options.javaPath : minecraftJava.path;
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
index 565b76c3..023e9bac 100644
--- a/src/Minecraft-Loader/index.ts
+++ b/src/Minecraft-Loader/index.ts
@@ -5,6 +5,7 @@
import { loader } from '../utils/Index.js';
import Forge from './loader/forge/forge.js';
+import NeoForge from './loader/neoForge/neoForge.js';
import Fabric from './loader/fabric/fabric.js';
import Quilt from './loader/quilt/quilt.js';
@@ -18,7 +19,7 @@ export default class Loader {
on: any;
emit: any;
- constructor(options) {
+ constructor(options: any) {
this.options = options
this.on = EventEmitter.prototype.on;
this.emit = EventEmitter.prototype.emit;
@@ -32,6 +33,10 @@ export default class Loader {
let forge = await this.forge(Loader);
if (forge.error) return this.emit('error', forge);
this.emit('json', forge);
+ } else if (this.options.loader.type === 'neoforge') {
+ let neoForge = await this.neoForge(Loader);
+ if (neoForge.error) return this.emit('error', neoForge);
+ this.emit('json', neoForge);
} else if (this.options.loader.type === 'fabric') {
let fabric = await this.fabric(Loader);
if (fabric.error) return this.emit('error', fabric);
@@ -66,7 +71,7 @@ export default class Loader {
});
// download installer
- let installer = await forge.donwloadInstaller(Loader);
+ let installer = await forge.downloadInstaller(Loader);
if (installer.error) return installer;
// extract install profile
@@ -91,6 +96,52 @@ export default class Loader {
return profile.version;
}
+ async neoForge(Loader: any) {
+ let neoForge = new NeoForge(this.options);
+
+ // set event
+ neoForge.on('check', (progress, size, element) => {
+ this.emit('check', progress, size, element);
+ });
+
+ neoForge.on('progress', (progress, size, element) => {
+ this.emit('progress', progress, size, element);
+ });
+
+ neoForge.on('extract', (element) => {
+ this.emit('extract', element);
+ });
+
+ neoForge.on('patch', patch => {
+ this.emit('patch', patch);
+ });
+
+ // download installer
+ let installer = await neoForge.downloadInstaller(Loader);
+ if (installer.error) return installer;
+
+ // extract install profile
+ let profile: any = await neoForge.extractProfile(installer.filePath);
+ if (profile.error) return profile
+ let destination = path.resolve(this.options.path, 'versions', profile.version.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
+
+ //extract universal jar
+ let universal: any = await neoForge.extractUniversalJar(profile.install, installer.filePath);
+ if (universal.error) return universal;
+
+ // download libraries
+ let libraries: any = await neoForge.downloadLibraries(profile, universal);
+ if (libraries.error) return libraries;
+
+ // patch forge if nessary
+ let patch: any = await neoForge.patchneoForge(profile.install);
+ if (patch.error) return patch;
+
+ return profile.version;
+ }
+
async fabric(Loader: any) {
let fabric = new Fabric(this.options);
@@ -116,6 +167,8 @@ export default class Loader {
return json;
}
+
+
async quilt(Loader: any) {
let quilt = new Quilt(this.options);
diff --git a/src/Minecraft-Loader/loader/fabric/fabric.ts b/src/Minecraft-Loader/loader/fabric/fabric.ts
index a7e9eb14..d8124a75 100644
--- a/src/Minecraft-Loader/loader/fabric/fabric.ts
+++ b/src/Minecraft-Loader/loader/fabric/fabric.ts
@@ -36,7 +36,7 @@ export default class FabricMC {
build = metaData.loader.find(loader => loader.version === this.options.loader.build);
}
- if (!build) return { error: `Fabric Loader ${this.options.loader.build} not fond, Available builds: ${AvailableBuilds.join(', ')}` };
+ if (!build) return { error: `Fabric Loader ${this.options.loader.build} not found, Available builds: ${AvailableBuilds.join(', ')}` };
let url = Loader.json.replace('${build}', build.version).replace('${version}', this.options.loader.version);
let json = await nodeFetch(url).then(res => res.json()).catch(err => err);
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index ea332b28..9afc18ec 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -5,7 +5,7 @@
import { getPathLibraries, getFileHash, mirrors, getFileFromJar } from '../../../utils/Index.js';
import download from '../../../utils/Downloader.js';
-import forgePatcher from './patcher.js'
+import forgePatcher from '../../patcher.js'
import nodeFetch from 'node-fetch'
import fs from 'fs'
@@ -23,7 +23,7 @@ export default class ForgeMC {
this.emit = EventEmitter.prototype.emit;
}
- async donwloadInstaller(Loader: any) {
+ async downloadInstaller(Loader: any) {
let metaData = (await nodeFetch(Loader.metaData).then(res => res.json()))[this.options.loader.version];
let AvailableBuilds = metaData;
let forgeURL = Loader.install
diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
new file mode 100644
index 00000000..fbf0271a
--- /dev/null
+++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
@@ -0,0 +1,226 @@
+/**
+ * @author Luuxis
+ * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
+ */
+
+import { getPathLibraries, getFileHash, mirrors, getFileFromJar } from '../../../utils/Index.js';
+import download from '../../../utils/Downloader.js';
+import neoForgePatcher from '../../patcher.js'
+
+import nodeFetch from 'node-fetch'
+import fs from 'fs'
+import path from 'path'
+import { EventEmitter } from 'events';
+
+export default class NeoForgeMC {
+ options: any;
+ on: any;
+ emit: any;
+
+ constructor(options = {}) {
+ this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async downloadInstaller(Loader: any) {
+ let build: string
+ let neoForgeURL = Loader.install
+ let metaData = await nodeFetch(Loader.metaData).then(res => res.json());
+
+ let versions = metaData.versions.filter(version => version.includes(`${this.options.loader.version}-`));
+ if (!versions.length) return { error: `NeoForge doesn't support Minecraft ${this.options.loader.version}` };
+
+ if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') {
+ build = versions[versions.length - 1];
+ } else build = versions.find(loader => loader === this.options.loader.build);
+
+ if (!build) return { error: `NeoForge Loader ${this.options.loader.build} not found, Available builds: ${versions.join(', ')}` };
+
+ neoForgeURL = neoForgeURL.replaceAll(/\${version}/g, build);
+
+
+ let pathFolder = path.resolve(this.options.path, 'neoForge');
+ let filePath = path.resolve(pathFolder, `forge-${build}-installer.jar`);
+
+ if (!fs.existsSync(filePath)) {
+ if (!fs.existsSync(pathFolder)) fs.mkdirSync(pathFolder, { recursive: true });
+ let downloadForge = new download();
+
+ downloadForge.on('progress', (downloaded, size) => {
+ this.emit('progress', downloaded, size, `forge-${build}-installer.jar`);
+ });
+
+ await downloadForge.downloadFile(neoForgeURL, pathFolder, `forge-${build}-installer.jar`);
+ }
+
+ return { filePath };
+ }
+
+ async extractProfile(pathInstaller: any) {
+ let neoForgeJSON: any = {}
+
+ let file: any = await getFileFromJar(pathInstaller, 'install_profile.json')
+ let neoForgeJsonOrigin = JSON.parse(file);
+
+ if (!neoForgeJsonOrigin) return { error: { message: 'Invalid neoForge installer' } };
+ if (neoForgeJsonOrigin.install) {
+ neoForgeJSON.install = neoForgeJsonOrigin.install;
+ neoForgeJSON.version = neoForgeJsonOrigin.versionInfo;
+ } else {
+ neoForgeJSON.install = neoForgeJsonOrigin;
+ let file: any = await getFileFromJar(pathInstaller, path.basename(neoForgeJSON.install.json))
+ neoForgeJSON.version = JSON.parse(file);
+ }
+
+ return neoForgeJSON;
+ }
+
+ async extractUniversalJar(profile: any, pathInstaller: any) {
+ let skipneoForgeFilter = true
+
+ if (profile.filePath) {
+ let fileInfo = getPathLibraries(profile.path)
+ this.emit('extract', `Extracting ${fileInfo.name}...`);
+
+ let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
+ if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
+
+ let file: any = await getFileFromJar(pathInstaller, profile.filePath)
+ fs.writeFileSync(`${pathFileDest}/${fileInfo.name}`, file, { mode: 0o777 })
+ } else if (profile.path) {
+ let fileInfo = getPathLibraries(profile.path)
+ let listFile: any = await getFileFromJar(pathInstaller, null, `maven/${fileInfo.path}`)
+
+ await Promise.all(
+ listFile.map(async (files: any) => {
+ let fileName = files.split('/')
+ this.emit('extract', `Extracting ${fileName[fileName.length - 1]}...`);
+ let file: any = await getFileFromJar(pathInstaller, files)
+ let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
+ if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
+ fs.writeFileSync(`${pathFileDest}/${fileName[fileName.length - 1]}`, file, { mode: 0o777 })
+ })
+ );
+ } else {
+ skipneoForgeFilter = false
+ }
+
+ if (profile.processors?.length) {
+ let universalPath = profile.libraries.find(v => {
+ return (v.name || '').startsWith('net.neoforged:forge')
+ })
+
+ let client: any = await getFileFromJar(pathInstaller, 'data/client.lzma');
+ let fileInfo = getPathLibraries(profile.path || universalPath.name, '-clientdata', '.lzma')
+ let pathFile = path.resolve(this.options.path, 'libraries', fileInfo.path)
+
+ if (!fs.existsSync(pathFile)) fs.mkdirSync(pathFile, { recursive: true });
+ fs.writeFileSync(`${pathFile}/${fileInfo.name}`, client, { mode: 0o777 })
+ this.emit('extract', `Extracting ${fileInfo.name}...`);
+ }
+
+ return skipneoForgeFilter
+ }
+
+ async downloadLibraries(profile: any, skipneoForgeFilter: any) {
+ let { libraries } = profile.version;
+ let downloader = new download();
+ let check = 0;
+ let files: any = [];
+ let size = 0;
+
+ if (profile.install.libraries) libraries = libraries.concat(profile.install.libraries);
+
+ libraries = libraries.filter((library, index, self) => index === self.findIndex(t => t.name === library.name))
+
+ let skipneoForge = [
+ 'net.minecraftforge:neoforged:',
+ 'net.minecraftforge:minecraftforge:'
+ ]
+
+ for (let lib of libraries) {
+ if (skipneoForgeFilter && skipneoForge.find(libs => lib.name.includes(libs))) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ if (lib.rules) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ let file = {}
+ let libInfo = getPathLibraries(lib.name);
+ let pathLib = path.resolve(this.options.path, 'libraries', libInfo.path);
+ let pathLibFile = path.resolve(pathLib, libInfo.name);
+
+ if (!fs.existsSync(pathLibFile)) {
+ let url
+ let sizeFile = 0
+
+ let baseURL = `${libInfo.path}/${libInfo.name}`;
+ let response: any = await downloader.checkMirror(baseURL, mirrors)
+
+ if (response?.status === 200) {
+ size += response.size;
+ sizeFile = response.size;
+ url = response.url;
+ } else if (lib.downloads?.artifact) {
+ url = lib.downloads.artifact.url
+ size += lib.downloads.artifact.size;
+ sizeFile = lib.downloads.artifact.size;
+ } else {
+ url = null
+ }
+
+ if (url == null || !url) {
+ return { error: `Impossible to download ${libInfo.name}` };
+ }
+
+ file = {
+ url: url,
+ folder: pathLib,
+ path: `${pathLib}/${libInfo.name}`,
+ name: libInfo.name,
+ size: sizeFile
+ }
+ files.push(file);
+ }
+ this.emit('check', check++, libraries.length, 'libraries');
+ }
+
+ if (files.length > 0) {
+ downloader.on("progress", (DL, totDL) => {
+ this.emit("progress", DL, totDL, 'libraries');
+ });
+
+ await downloader.downloadFileMultiple(files, size, this.options.downloadFileMultiple);
+ }
+ return libraries
+ }
+
+ async patchneoForge(profile: any) {
+ if (profile?.processors?.length) {
+ let patcher: any = new neoForgePatcher(this.options);
+ let config: any = {}
+
+ patcher.on('patch', data => {
+ this.emit('patch', data);
+ });
+
+ patcher.on('error', data => {
+ this.emit('error', data);
+ });
+
+ if (!patcher.check(profile)) {
+ config = {
+ java: this.options.loader.config.javaPath,
+ minecraft: this.options.loader.config.minecraftJar,
+ minecraftJson: this.options.loader.config.minecraftJson
+ }
+
+ await patcher.patcher(profile, config);
+ }
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/Minecraft-Loader/loader/quilt/quilt.ts b/src/Minecraft-Loader/loader/quilt/quilt.ts
index 1e6f550a..1e418d9a 100644
--- a/src/Minecraft-Loader/loader/quilt/quilt.ts
+++ b/src/Minecraft-Loader/loader/quilt/quilt.ts
@@ -39,7 +39,7 @@ export default class Quilt {
build = metaData.loader.find(loader => loader.version === this.options.loader.build);
}
- if (!build) return { error: `QuiltMC Loader ${this.options.loader.build} not fond, Available builds: ${AvailableBuilds.join(', ')}` };
+ if (!build) return { error: `QuiltMC Loader ${this.options.loader.build} not found, Available builds: ${AvailableBuilds.join(', ')}` };
let url = Loader.json.replace('${build}', build.version).replace('${version}', this.options.loader.version);
let json = await nodeFetch(url).then(res => res.json()).catch(err => err);
diff --git a/src/Minecraft-Loader/loader/forge/patcher.ts b/src/Minecraft-Loader/patcher.ts
similarity index 93%
rename from src/Minecraft-Loader/loader/forge/patcher.ts
rename to src/Minecraft-Loader/patcher.ts
index 8c46214c..b8de04e5 100644
--- a/src/Minecraft-Loader/loader/forge/patcher.ts
+++ b/src/Minecraft-Loader/patcher.ts
@@ -3,7 +3,7 @@ import fs from 'fs'
import path from 'path'
import { EventEmitter } from 'events';
-import { getPathLibraries, getFileFromJar } from '../../../utils/Index.js';
+import { getPathLibraries, getFileFromJar } from '../utils/Index.js';
@@ -101,9 +101,10 @@ export default class forgePatcher {
setArgument(arg: any, profile: any, config: any) {
let finalArg = arg.replace('{', '').replace('}', '');
- let universalPath = profile.libraries.find(v =>
- (v.name || '').startsWith('net.minecraftforge:forge')
- )
+ let universalPath = profile.libraries.find(v => {
+ if (this.options.loader.type === 'forge') return (v.name || '').startsWith('net.minecraftforge:forge')
+ if (this.options.loader.type === 'neoforge') return (v.name || '').startsWith('net.neoforged:forge')
+ })
if (profile.data[finalArg]) {
if (finalArg === 'BINPATCH') {
diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts
index 36a41e67..79613a31 100755
--- a/src/Minecraft/Minecraft-Arguments.ts
+++ b/src/Minecraft/Minecraft-Arguments.ts
@@ -23,7 +23,8 @@ export default class MinecraftArguments {
return {
game: game,
jvm: jvm,
- classpath: classpath
+ classpath: classpath.classpath,
+ mainClass: classpath.mainClass
}
}
@@ -88,12 +89,11 @@ export default class MinecraftArguments {
'-Dfml.ignoreInvalidMinecraftCertificates=true'
]
- if (process.platform == 'darwin') {
- if (!json.minecraftArguments) {
- jvm.push(opts[process.platform])
- }
+ if (!json.minecraftArguments) {
+ jvm.push(opts[process.platform])
}
+
if (json.nativesList) {
jvm.push(`-Djava.library.path=${this.options.path}/versions/${json.id}/natives`)
}
@@ -131,10 +131,11 @@ export default class MinecraftArguments {
}
classPath.push(`${this.options.path}/versions/${json.id}/${json.id}.jar`)
- return [
+ return {classpath:[
`-cp`,
classPath.join(process.platform === 'win32' ? ';' : ':'),
- loaderJson ? loaderJson.mainClass : json.mainClass
- ]
+
+ ],
+ mainClass: loaderJson ? loaderJson.mainClass : json.mainClass}
}
}
diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts
index 1f60f107..a96c7fc2 100755
--- a/src/Minecraft/Minecraft-Loader.ts
+++ b/src/Minecraft/Minecraft-Loader.ts
@@ -82,7 +82,7 @@ export default class MinecraftLoader {
if (moddeArguments.jvm) Arguments.jvm = moddeArguments.jvm.map(jvm => {
return jvm
.replace(/\${version_name}/g, version)
- .replace(/\${library_directory}/g, `${this.options.path}/loader/${this.options.loader.type}/libraries`)
+ .replace(/\${library_directory}/g, `${this.options.path}/loader/${this.options.loader.type.toLowerCase()}/libraries`)
.replace(/\${classpath_separator}/g, process.platform === 'win32' ? ';' : ':');
})
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index 9fc4eb4d..c530f358 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -45,7 +45,11 @@ function loader(type: string) {
meta: 'https://files.minecraftforge.net/net/minecraftforge/forge/${build}/meta.json',
promotions: 'https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json',
install: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-installer.jar'
-
+ }
+ } else if (type === 'neoforge') {
+ return {
+ metaData: 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge',
+ install: 'https://maven.neoforged.net/net/neoforged/forge/${version}/forge-${version}-installer.jar'
}
} else if (type === 'fabric') {
return {
@@ -63,6 +67,7 @@ function loader(type: string) {
let mirrors = [
"https://maven.minecraftforge.net",
+ "https://maven.neoforged.net/releases",
"https://maven.creeperhost.net",
"https://libraries.minecraft.net"
]
diff --git a/test/3D/index.html b/test/3D/index.html
deleted file mode 100755
index ad267ef5..00000000
--- a/test/3D/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- My first three.js app
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/3D/index.js b/test/3D/index.js
deleted file mode 100755
index 724de854..00000000
--- a/test/3D/index.js
+++ /dev/null
@@ -1,24 +0,0 @@
-let skinUrl = 'http://textures.minecraft.net/texture/ac3de5b50fb6174da51032677ead046295486bf682b3ea73e0617a210c4b4f46'
-
-const scene = new THREE.Scene();
-const camera = new THREE.PerspectiveCamera(75, 1000 / 500, 0.1, 100);
-
-const renderer = new THREE.WebGLRenderer();
-renderer.setSize(1000, 500);
-document.body.appendChild(renderer.domElement);
-
-const geometry = new THREE.BoxGeometry(1, 1, 1);
-const material = new THREE.MeshBasicMaterial({ color: '#F1F1F1'});
-const cube = new THREE.Mesh(geometry, material);
-scene.add(cube);
-
-camera.position.z = 2;
-
-function animate() {
- requestAnimationFrame(animate);
- cube.rotation.x += 0.01;
- cube.rotation.y += 0.05;
- renderer.render(scene, camera);
-};
-
-animate();
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 91e077d3..f9bcc974 100755
--- a/test/index.js
+++ b/test/index.js
@@ -1,3 +1,4 @@
+const { spawn } = require('child_process');
const { Microsoft, Launch, Mojang } = require('../build/Index');
const launch = new Launch();
const fs = require('fs');
@@ -32,8 +33,8 @@ let mc
downloadFileMultiple: 30,
loader: {
- type: 'fabric',
- build: '0.14.22',
+ type: 'neoForge',
+ build: 'latest',
enable: true
},
@@ -107,3 +108,25 @@ let mc
console.log(err);
});
})()
+
+// const VERSIONS_ENDPOINT = 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge'
+// const DOWNLOAD_URL = 'https://maven.neoforged.net/net/neoforged/forge';
+
+// (async () => {
+// let versionJson;
+
+// const response = await fetch(VERSIONS_ENDPOINT);
+// versionJson = await response.json();
+
+// if (versionJson) {
+// let { versions } = versionJson;
+// console.log(versions);
+
+// versions = versions[1];
+
+// const installerUrl = `${DOWNLOAD_URL}/${versions}/forge-${versions}-installer.jar`;
+
+// console.log(installerUrl);
+
+// }
+// })()
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 076ada6f..a473eadc 100755
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,8 +6,10 @@
"sourceMap": false,
"target": "ES2020",
"module": "CommonJS",
- "lib": ["ES2021"],
- "declaration": true,
+ "lib": [
+ "ES2021"
+ ],
+ "declaration": true,
"outDir": "build",
"esModuleInterop": true
}
From 415a0c874a85b51d391a9db261ef03ca971da0cb Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 12 Aug 2023 23:25:17 +0200
Subject: [PATCH 004/185] add support legacyfabric
---
src/Minecraft-Loader/index.ts | 28 ++++++
.../loader/legacyfabric/legacyFabric.ts | 94 +++++++++++++++++++
src/utils/Downloader.ts | 3 +-
src/utils/Index.ts | 5 +
test/index.js | 4 +-
5 files changed, 131 insertions(+), 3 deletions(-)
create mode 100644 src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
index 023e9bac..14cca954 100644
--- a/src/Minecraft-Loader/index.ts
+++ b/src/Minecraft-Loader/index.ts
@@ -7,6 +7,7 @@ import { loader } from '../utils/Index.js';
import Forge from './loader/forge/forge.js';
import NeoForge from './loader/neoForge/neoForge.js';
import Fabric from './loader/fabric/fabric.js';
+import LegacyFabric from './loader/legacyfabric/legacyFabric.js';
import Quilt from './loader/quilt/quilt.js';
@@ -41,6 +42,10 @@ export default class Loader {
let fabric = await this.fabric(Loader);
if (fabric.error) return this.emit('error', fabric);
this.emit('json', fabric);
+ } else if (this.options.loader.type === 'legacyfabric') {
+ let legacyFabric = await this.legacyFabric(Loader);
+ if (legacyFabric.error) return this.emit('error', legacyFabric);
+ this.emit('json', legacyFabric);
} else if (this.options.loader.type === 'quilt') {
let quilt = await this.quilt(Loader);
if (quilt.error) return this.emit('error', quilt);
@@ -167,7 +172,30 @@ export default class Loader {
return json;
}
+ async legacyFabric(Loader: any) {
+ let legacyFabric = new LegacyFabric(this.options);
+ // set event
+ legacyFabric.on('check', (progress, size, element) => {
+ this.emit('check', progress, size, element);
+ });
+
+ legacyFabric.on('progress', (progress, size, element) => {
+ this.emit('progress', progress, size, element);
+ });
+
+ // download Json
+ let json = await legacyFabric.downloadJson(Loader);
+ if (json.error) return json;
+ let destination = path.resolve(this.options.path, 'versions', json.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${json.id}.json`), JSON.stringify(json, null, 4));
+
+ // download libraries
+ await legacyFabric.downloadLibraries(json);
+
+ return json;
+ }
async quilt(Loader: any) {
let quilt = new Quilt(this.options);
diff --git a/src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts b/src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts
new file mode 100644
index 00000000..d8124a75
--- /dev/null
+++ b/src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts
@@ -0,0 +1,94 @@
+/**
+ * @author Luuxis
+ * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
+ */
+
+import { getPathLibraries } from '../../../utils/Index.js';
+import download from '../../../utils/Downloader.js';
+
+import nodeFetch from 'node-fetch'
+import fs from 'fs'
+import path from'path'
+import { EventEmitter } from 'events';
+
+export default class FabricMC {
+ options: any;
+ on: any;
+ emit: any;
+
+ constructor(options = {}) {
+ this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
+ }
+
+ async downloadJson(Loader) {
+ let build
+ let metaData = await nodeFetch(Loader.metaData).then(res => res.json());
+
+ let version = metaData.game.find(version => version.version === this.options.loader.version);
+ let AvailableBuilds = metaData.loader.map(build => build.version);
+ if (!version) return { error: `FabricMC doesn't support Minecraft ${this.options.loader.version}` };
+
+ if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') {
+ build = metaData.loader[0];
+ } else {
+ build = metaData.loader.find(loader => loader.version === this.options.loader.build);
+ }
+
+ if (!build) return { error: `Fabric Loader ${this.options.loader.build} not found, Available builds: ${AvailableBuilds.join(', ')}` };
+
+ let url = Loader.json.replace('${build}', build.version).replace('${version}', this.options.loader.version);
+ let json = await nodeFetch(url).then(res => res.json()).catch(err => err);
+ return json
+ }
+
+ async downloadLibraries(json) {
+ let { libraries } = json;
+ let downloader = new download();
+ let files:any = [];
+ let check = 0;
+ let size = 0;
+
+ for (let lib of libraries) {
+ if (lib.rules) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
+ let file = {}
+ let libInfo = getPathLibraries(lib.name);
+ let pathLib = path.resolve(this.options.path, 'libraries', libInfo.path);
+ let pathLibFile = path.resolve(pathLib, libInfo.name);
+
+ if (!fs.existsSync(pathLibFile)) {
+ let url = `${lib.url}${libInfo.path}/${libInfo.name}`
+ let sizeFile = 0
+
+ let res:any = await downloader.checkURL(url);
+ if (res.status === 200) {
+ sizeFile = res.size;
+ size += res.size;
+ }
+
+ file = {
+ url: url,
+ folder: pathLib,
+ path: `${pathLib}/${libInfo.name}`,
+ name: libInfo.name,
+ size: sizeFile
+ }
+ files.push(file);
+ }
+ this.emit('check', check++, libraries.length, 'libraries');
+ }
+
+ if (files.length > 0) {
+ downloader.on("progress", (DL, totDL) => {
+ this.emit("progress", DL, totDL, 'libraries');
+ });
+
+ await downloader.downloadFileMultiple(files, size, this.options.downloadFileMultiple);
+ }
+ return libraries
+ }
+}
\ No newline at end of file
diff --git a/src/utils/Downloader.ts b/src/utils/Downloader.ts
index 660dfc23..a85b97e6 100755
--- a/src/utils/Downloader.ts
+++ b/src/utils/Downloader.ts
@@ -27,8 +27,9 @@ export default class download {
if (!fs.existsSync(path)) fs.mkdirSync(path, { recursive: true });
const writer = fs.createWriteStream(path + '/' + fileName);
const response = await nodeFetch(url);
- const size = response.headers.get('content-length');
+ let size = response.headers.get('content-length');
let downloaded = 0;
+
return new Promise((resolve: any, reject: any) => {
response.body.on('data', (chunk) => {
downloaded += chunk.length;
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index c530f358..8891e313 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -56,6 +56,11 @@ function loader(type: string) {
metaData: 'https://meta.fabricmc.net/v2/versions',
json: 'https://meta.fabricmc.net/v2/versions/loader/${version}/${build}/profile/json'
}
+ } else if (type === 'legacyfabric') {
+ return {
+ metaData: 'https://meta.legacyfabric.net/v2/versions',
+ json: 'https://meta.legacyfabric.net/v2/versions/loader/${version}/${build}/profile/json'
+ }
} else if (type === 'quilt') {
return {
metaData: 'https://meta.quiltmc.org/v3/versions',
diff --git a/test/index.js b/test/index.js
index f9bcc974..18725b62 100755
--- a/test/index.js
+++ b/test/index.js
@@ -28,12 +28,12 @@ let mc
timeout: 10000,
path: './.Minecraft',
instance: 'Hypixel',
- version: '1.20.1',
+ version: '1.12.2',
detached: false,
downloadFileMultiple: 30,
loader: {
- type: 'neoForge',
+ type: 'legacyfabric',
build: 'latest',
enable: true
},
From ddfc121e5d0e3cf232d35135b9a7c30c9b0c6af5 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 12 Aug 2023 23:57:16 +0200
Subject: [PATCH 005/185] hide prive info console (token ...)
---
src/Launch.ts | 10 ++++++++--
test/index.js | 4 ++--
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 3a2f2f06..c6814565 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -100,9 +100,15 @@ export default class Launch {
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 minecraftDebug = spawn(java, Arguments, { cwd: logs, detached: this.options.detached })
+ let argumentsLogs: string = Arguments.join(' ')
+ argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.access_token, '__HIDDEN_TOKEN__')
+ argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.client_token, '__HIDDEN_TOKEN__')
+ argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.uuid, '__HIDDEN_UUID__')
+ argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.xuid, '__HIDDEN_XUID__')
+ argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, '')
+ this.emit('data', `Launching with arguments ${argumentsLogs}`);
- this.emit('data', `Launching with arguments ${Arguments.join(' ')}`)
+ 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'))
diff --git a/test/index.js b/test/index.js
index 18725b62..8de363dd 100755
--- a/test/index.js
+++ b/test/index.js
@@ -28,12 +28,12 @@ let mc
timeout: 10000,
path: './.Minecraft',
instance: 'Hypixel',
- version: '1.12.2',
+ version: '1.20.1',
detached: false,
downloadFileMultiple: 30,
loader: {
- type: 'legacyfabric',
+ type: 'Forge',
build: 'latest',
enable: true
},
From b6e887e3592ef14ac19156ba6a1c937dec50cd37 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 12 Aug 2023 23:58:06 +0200
Subject: [PATCH 006/185] publish 3.6.1
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 11301c28..84b3465f 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.6.0",
+ "version": "3.6.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.6.0",
+ "version": "3.6.1",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 7240516a..7edd54d9 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.6.0",
+ "version": "3.6.1",
"types": "./build/Index.d.ts",
"exports": {
".": {
From 31899c3372d3d22aacfcabdd5589523d2a8555e4 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sun, 13 Aug 2023 00:09:14 +0200
Subject: [PATCH 007/185] Update index.js
---
test/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/index.js b/test/index.js
index 8de363dd..f9bcc974 100755
--- a/test/index.js
+++ b/test/index.js
@@ -33,7 +33,7 @@ let mc
downloadFileMultiple: 30,
loader: {
- type: 'Forge',
+ type: 'neoForge',
build: 'latest',
enable: true
},
From aa93c7b43dc77ee66f6cf4bf043d2ac4c9803e4e Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sun, 13 Aug 2023 00:10:44 +0200
Subject: [PATCH 008/185] Update Launch.ts
---
src/Launch.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index c6814565..5bf6e834 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -101,10 +101,10 @@ export default class Launch {
if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true });
let argumentsLogs: string = Arguments.join(' ')
- argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.access_token, '__HIDDEN_TOKEN__')
- argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.client_token, '__HIDDEN_TOKEN__')
- argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.uuid, '__HIDDEN_UUID__')
- argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator.xuid, '__HIDDEN_XUID__')
+ 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.xuid, '????????')
argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, '')
this.emit('data', `Launching with arguments ${argumentsLogs}`);
From 0ddc5be79e6ad352f8f99092a9ba413681b01456 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Thu, 17 Aug 2023 19:25:24 +0200
Subject: [PATCH 009/185] fix
---
src/Minecraft/Minecraft-Assets.ts | 3 ++-
test/index.js | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/Minecraft/Minecraft-Assets.ts b/src/Minecraft/Minecraft-Assets.ts
index 7d47d8ed..9bf38caa 100755
--- a/src/Minecraft/Minecraft-Assets.ts
+++ b/src/Minecraft/Minecraft-Assets.ts
@@ -40,7 +40,8 @@ export default class MinecraftAssets {
}
copyAssets(json: any) {
- let legacyDirectory = `${this.options.path}/resources`;
+ let legacyDirectory: string = `${this.options.path}/resources`;
+ if (this.options.instance) legacyDirectory = `${this.options.path}/instances/${this.options.instance}/resources`;
let pathAssets = `${this.options.path}/assets/indexes/${json.assets}.json`;
if (!fs.existsSync(pathAssets)) return;
let assets = JSON.parse(fs.readFileSync(pathAssets, 'utf-8'));
diff --git a/test/index.js b/test/index.js
index f9bcc974..707d7782 100755
--- a/test/index.js
+++ b/test/index.js
@@ -28,12 +28,12 @@ let mc
timeout: 10000,
path: './.Minecraft',
instance: 'Hypixel',
- version: '1.20.1',
+ version: '1.4.7',
detached: false,
downloadFileMultiple: 30,
loader: {
- type: 'neoForge',
+ type: 'legacyFabric',
build: 'latest',
enable: true
},
From 5ef62caed67054a3805b649528ed9628d97bc7a9 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sun, 20 Aug 2023 22:48:38 +0200
Subject: [PATCH 010/185] change path java
---
src/Minecraft/Minecraft-Java.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 8af5e865..6860b859 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -42,7 +42,7 @@ export default class java {
if (info.type == "directory") continue;
if (!info.downloads) continue;
let file: any = {};
- file.path = `runtime/${version}/${path.replace(toDelete, "")}`;
+ file.path = `runtime/${version}-${process.platform}/${path.replace(toDelete, "")}`;
file.executable = info.executable;
file.sha1 = info.downloads.raw.sha1;
file.size = info.downloads.raw.size;
@@ -52,7 +52,7 @@ export default class java {
}
return {
files: files,
- path: path.resolve(this.options.path, `runtime/${version}/bin/java${process.platform == "win32" ? ".exe" : ""}`).replace(/\\/g, "/"),
+ path: path.resolve(this.options.path, `runtime/${version}-${process.platform}/bin/java${process.platform == "win32" ? ".exe" : ""}`),
};
}
}
\ No newline at end of file
From 9962457c6db6f60946f62a107680507de85c5799 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 22 Aug 2023 04:36:46 +0200
Subject: [PATCH 011/185] publish 3.6.2
---
README.md | 8 +++++---
package-lock.json | 4 ++--
package.json | 2 +-
test/index.js | 8 ++++----
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index dec625ec..69e27635 100755
--- a/README.md
+++ b/README.md
@@ -122,6 +122,8 @@ async function main() {
main()
```
---
-
-
-[
](https://discord.gg/e9q7Yr2cuQ)
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 84b3465f..66e89901 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.6.1",
+ "version": "3.6.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.6.1",
+ "version": "3.6.2",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 7edd54d9..c03c922b 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.6.1",
+ "version": "3.6.2",
"types": "./build/Index.d.ts",
"exports": {
".": {
diff --git a/test/index.js b/test/index.js
index 707d7782..8331d481 100755
--- a/test/index.js
+++ b/test/index.js
@@ -23,17 +23,17 @@ let mc
}
let opt = {
- // url: 'http://craftdium.ml/launcherSelvania/files?instance=hypixel',
+ url: 'http://launcher.luuxis.fr/files=?instance=PokeMoonX',
authenticator: mc,
timeout: 10000,
path: './.Minecraft',
- instance: 'Hypixel',
- version: '1.4.7',
+ instance: 'PokeMoonX',
+ version: '1.16.5',
detached: false,
downloadFileMultiple: 30,
loader: {
- type: 'legacyFabric',
+ type: 'forge',
build: 'latest',
enable: true
},
From 1394daf5d6f7767d4f3c88ff79a4f3e43db1d8c5 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 22 Aug 2023 04:41:25 +0200
Subject: [PATCH 012/185] publish 3.6.2
---
README.md | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 69e27635..6da61b20 100755
--- a/README.md
+++ b/README.md
@@ -2,13 +2,16 @@
NodeJS Module for Minecraft launcher
[](https://npmjs.com/minecraft-java-core)
-
[](https://npmjs.com/minecraft-java-core)
-
[](https://npmjs.com/minecraft-java-core)
-
[](https://npmjs.com/minecraft-java-core)
+
+
+
+
+
+
---
## Avantages :dizzy:
- Auto check & downloading compatible java version
@@ -121,9 +124,3 @@ async function main() {
main()
```
----
-
-
-
-
-
From d86d8635fd06e9feaa8141b0f3bc43d2f0271416 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Thu, 31 Aug 2023 23:24:36 +0200
Subject: [PATCH 013/185] fix path files verify
---
src/Launch.ts | 2 +-
src/Minecraft/Minecraft-Bundle.ts | 19 ++++++-------------
src/utils/Index.ts | 4 ++--
3 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 5bf6e834..6ef3c959 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -71,7 +71,7 @@ export default class Launch {
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 > 20) this.options.downloadFileMultiple = 20
+ if (this.options.downloadFileMultiple > 30) this.options.downloadFileMultiple = 30
if (!this.options.loader.enable) this.options.loader = false;
this.start();
}
diff --git a/src/Minecraft/Minecraft-Bundle.ts b/src/Minecraft/Minecraft-Bundle.ts
index 8e032680..0286e1bc 100755
--- a/src/Minecraft/Minecraft-Bundle.ts
+++ b/src/Minecraft/Minecraft-Bundle.ts
@@ -28,16 +28,15 @@ export default class MinecraftBundle {
}
if (fs.existsSync(file.path)) {
- if (this.options.ignored.find(ignored => ignored == file.path.split("/").slice(-1)[0])) continue
+ if (this.options.ignored.find(ignored => ignored == file.path.replaceAll(`${this.options.path}/`, ""))) continue
+
if (file.sha1) {
if (await getFileHash(file.path) != file.sha1) {
todownload.push(file);
}
}
- } else {
- todownload.push(file);
- }
+ } else todownload.push(file);
}
return todownload;
}
@@ -52,19 +51,13 @@ export default class MinecraftBundle {
async checkFiles(bundle: any) {
let instancePath = ''
- let instanceFolder = []
if (this.options.instance) {
if (!fs.existsSync(`${this.options.path}/instances`)) fs.mkdirSync(`${this.options.path}/instances`, { recursive: true });
instancePath = `/instances/${this.options.instance}`
- instanceFolder = fs.readdirSync(`${this.options.path}/instances`).filter(dir => dir != this.options.instance)
}
- let files = this.getFiles(this.options.path);
+ let files = this.options.instance ? this.getFiles(`${this.options.path}/instances/${this.options.instance}`) : this.getFiles(this.options.path);
let ignoredfiles = [...this.getFiles(`${this.options.path}/loader`)]
- for (let instances of instanceFolder) {
- ignoredfiles.push(...this.getFiles(`${this.options.path}/instances/${instances}`));
- }
-
for (let file of this.options.ignored) {
file = (`${this.options.path}${instancePath}/${file}`)
if (fs.existsSync(file)) {
@@ -83,14 +76,14 @@ export default class MinecraftBundle {
for (let file of files) {
try {
if (fs.statSync(file).isDirectory()) {
- fs.rmdirSync(file);
+ fs.rmSync(file, { recursive: true });
} else {
fs.unlinkSync(file);
let folder = file.split("/").slice(0, -1).join("/");
while (true) {
if (folder == this.options.path) break;
let content = fs.readdirSync(folder);
- if (content.length == 0) fs.rmdirSync(folder);
+ if (content.length == 0) fs.rmSync(folder);
folder = folder.split("/").slice(0, -1).join("/");
}
}
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index 8891e313..7fb407ab 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -88,8 +88,8 @@ async function getFileFromJar(jar: string, file: string = null, path: string = n
if (entry.entryName == file) fileReturn = entry.getData();
}
- if (!entry.isDirectory && entry.entryName.includes(path)) {
- fileReturn.push(entry.entryName)
+ if (!entry.isDirectory && entry.entryName.includes(path) && path) {
+ fileReturn.push(entry.entryName);
}
}
resolve(fileReturn);
From 339d75792edc61c13822d30f11a092d6214f8ee1 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Thu, 31 Aug 2023 23:24:56 +0200
Subject: [PATCH 014/185] publish 3.6.3
---
package-lock.json | 4 ++--
package.json | 2 +-
test/index.js | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 66e89901..815fcb50 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.6.2",
+ "version": "3.6.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.6.2",
+ "version": "3.6.3",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index c03c922b..03d46f00 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.6.2",
+ "version": "3.6.3",
"types": "./build/Index.d.ts",
"exports": {
".": {
diff --git a/test/index.js b/test/index.js
index 8331d481..16561bf4 100755
--- a/test/index.js
+++ b/test/index.js
@@ -23,7 +23,7 @@ let mc
}
let opt = {
- url: 'http://launcher.luuxis.fr/files=?instance=PokeMoonX',
+ url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
authenticator: mc,
timeout: 10000,
path: './.Minecraft',
@@ -33,12 +33,12 @@ let mc
downloadFileMultiple: 30,
loader: {
- type: 'forge',
+ type: 'Forge',
build: 'latest',
enable: true
},
- verify: false,
+ verify: true,
ignored: [
'config',
'essential',
From a2946ed251e78f30a710b5f00a5549db378e9b6c Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 5 Sep 2023 13:36:17 +0200
Subject: [PATCH 015/185] del test neoforge
---
.gitignore | 1 +
test/index.js | 31 ++++---------------------------
2 files changed, 5 insertions(+), 27 deletions(-)
diff --git a/.gitignore b/.gitignore
index 08dc1a24..453cb7e9 100755
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ files
.Minecraft
test/*.json
webfiles/instances/*
+.DS_Store
diff --git a/test/index.js b/test/index.js
index 16561bf4..16486a83 100755
--- a/test/index.js
+++ b/test/index.js
@@ -1,5 +1,4 @@
-const { spawn } = require('child_process');
-const { Microsoft, Launch, Mojang } = require('../build/Index');
+const { Microsoft, Launch } = require('../build/Index');
const launch = new Launch();
const fs = require('fs');
@@ -23,12 +22,12 @@ let mc
}
let opt = {
- url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
+ //url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
authenticator: mc,
timeout: 10000,
path: './.Minecraft',
instance: 'PokeMoonX',
- version: '1.16.5',
+ version: '1.20.1',
detached: false,
downloadFileMultiple: 30,
@@ -107,26 +106,4 @@ let mc
launch.on('error', err => {
console.log(err);
});
-})()
-
-// const VERSIONS_ENDPOINT = 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge'
-// const DOWNLOAD_URL = 'https://maven.neoforged.net/net/neoforged/forge';
-
-// (async () => {
-// let versionJson;
-
-// const response = await fetch(VERSIONS_ENDPOINT);
-// versionJson = await response.json();
-
-// if (versionJson) {
-// let { versions } = versionJson;
-// console.log(versions);
-
-// versions = versions[1];
-
-// const installerUrl = `${DOWNLOAD_URL}/${versions}/forge-${versions}-installer.jar`;
-
-// console.log(installerUrl);
-
-// }
-// })()
\ No newline at end of file
+})()
\ No newline at end of file
From 1e9b5407e6f98b72bb253039feb83cd5a1f48602 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Mon, 11 Sep 2023 11:23:35 +0200
Subject: [PATCH 016/185] add suport minecraft 1.0 > 1.18 arm
---
src/Launch.ts | 2 ++
src/Minecraft/Minecraft-Java.ts | 20 +++++++++++++-------
test/index.js | 14 +++++++-------
3 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 6ef3c959..817593be 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -128,6 +128,8 @@ export default class Launch {
let gameAssets: any = await new assetsMinecraft(this.options).GetAssets(json);
let gameJava: any = this.options.javaPath ? { files: [] } : await new javaMinecraft(this.options).GetJsonJava(json);
+ if (gameJava.error) return gameJava
+
let filesList: any = await bundle.checkBundle([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]);
if (filesList.length > 0) {
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 6860b859..854a37bf 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -23,18 +23,23 @@ export default class java {
if (os.platform() == "win32") {
let arch = { x64: "windows-x64", ia32: "windows-x86" }
- version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].version.name}`
- javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].manifest.url).then(res => res.json())).files)
+ version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
+ if (version.includes('undefined')) return { error: true, message: "Java not found" };
+ javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
} else if (os.platform() == "darwin") {
- let arch = { x64: "mac-os", arm64: "mac-os-arm64" }
- version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].version.name}`
- javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].manifest.url).then(res => res.json())).files)
+ let arch = { x64: "mac-os", arm64: "mac-os" }
+ version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
+ if (version.includes('undefined')) return { error: true, message: "Java not found" };
+ javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
} else if (os.platform() == "linux") {
let arch = { x64: "linux", ia32: "linux-i386" }
- version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].version.name}`
- javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].manifest.url).then(res => res.json())).files)
+ version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
+ if (version.includes('undefined')) return { error: true, message: "Java not found" };
+ javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
} else return console.log("OS not supported");
+ if (!javaVersionsJson) return { error: true, message: "Java not found" };
+
let java = javaVersionsJson.find(file => file[0].endsWith(process.platform == "win32" ? "bin/javaw.exe" : "bin/java"))[0];
let toDelete = java.replace(process.platform == "win32" ? "bin/javaw.exe" : "bin/java", "");
@@ -54,5 +59,6 @@ export default class java {
files: files,
path: path.resolve(this.options.path, `runtime/${version}-${process.platform}/bin/java${process.platform == "win32" ? ".exe" : ""}`),
};
+
}
}
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 16486a83..8981c259 100755
--- a/test/index.js
+++ b/test/index.js
@@ -22,12 +22,12 @@ let mc
}
let opt = {
- //url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
+ url: 'https://launcher.luuxis.fr/files/?instance=hypixel',
authenticator: mc,
timeout: 10000,
path: './.Minecraft',
- instance: 'PokeMoonX',
- version: '1.20.1',
+ instance: 'Hypixel',
+ version: '1.8.9',
detached: false,
downloadFileMultiple: 30,
@@ -55,10 +55,10 @@ let mc
javaPath: null,
- screen: {
- width: 1600,
- height: 900
- },
+ //screen: {
+ // width: 1600,
+ // height: 900
+ //},
memory: {
min: '4G',
From 7582e03b73846234d82e1b58e09d25f54d3eebaa Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Mon, 11 Sep 2023 11:30:18 +0200
Subject: [PATCH 017/185] pulish 3.6.4
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 815fcb50..311f71dd 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.6.3",
+ "version": "3.6.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.6.3",
+ "version": "3.6.4",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 03d46f00..e19363e0 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.6.3",
+ "version": "3.6.4",
"types": "./build/Index.d.ts",
"exports": {
".": {
From fa8410e669a499c65a4a41bf3bbf01290230133d Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 13 Sep 2023 11:05:18 +0200
Subject: [PATCH 018/185] test
---
src/Launch.ts | 1 +
src/Minecraft/Minecraft-Java.ts | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 817593be..219125fd 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -43,6 +43,7 @@ export default class Launch {
instance: opt?.instance || null,
detached: opt?.detached || false,
downloadFileMultiple: opt?.downloadFileMultiple || 3,
+ armEnabledMac: opt?.armEnabledMac || true,
loader: {
type: opt?.loader?.type?.toLowerCase() || null,
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 854a37bf..d3d98464 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -27,7 +27,7 @@ export default class java {
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
} else if (os.platform() == "darwin") {
- let arch = { x64: "mac-os", arm64: "mac-os" }
+ let arch = { x64: "mac-os", arm64: this.options.armEnabledMac ? "mac-os-arm64" : "mac-os" }
version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
From 3320283541870fb63d8f8b1b2c6faf8668faa78e Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 27 Sep 2023 17:57:29 +0200
Subject: [PATCH 019/185] add suport mac silicn
---
package-lock.json | 10 ++++++++++
package.json | 1 +
src/Launch.ts | 2 +-
src/Minecraft-Loader/patcher.ts | 2 --
src/Minecraft/Minecraft-Java.ts | 2 +-
src/utils/Index.ts | 2 +-
test/index.js | 9 +++++----
7 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 311f71dd..5c7a1c3a 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"tslib": "^2.4.1"
},
"devDependencies": {
+ "@types/adm-zip": "^0.5.2",
"@types/node": "^18.11.13",
"@types/node-fetch": "^2.6.2",
"rimraf": "^3.0.2",
@@ -29,6 +30,15 @@
"node": ">=0.1.90"
}
},
+ "node_modules/@types/adm-zip": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.2.tgz",
+ "integrity": "sha512-33OTTnnW3onOE6HJuoqsi7T7Ojupz7zO/Vs5ddRNVCYQnu4lg05RqH/pr9eidHGvGyYfdO4uPO9cvegAMixBCQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/node": {
"version": "18.13.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
diff --git a/package.json b/package.json
index e19363e0..ac6f790d 100755
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"tslib": "^2.4.1"
},
"devDependencies": {
+ "@types/adm-zip": "^0.5.2",
"@types/node": "^18.11.13",
"@types/node-fetch": "^2.6.2",
"rimraf": "^3.0.2",
diff --git a/src/Launch.ts b/src/Launch.ts
index 219125fd..cd972be6 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -43,7 +43,7 @@ export default class Launch {
instance: opt?.instance || null,
detached: opt?.detached || false,
downloadFileMultiple: opt?.downloadFileMultiple || 3,
- armEnabledMac: opt?.armEnabledMac || true,
+ intelEnabledMac: opt?.intelEnabledMac ? true : false,
loader: {
type: opt?.loader?.type?.toLowerCase() || null,
diff --git a/src/Minecraft-Loader/patcher.ts b/src/Minecraft-Loader/patcher.ts
index b8de04e5..bc9452de 100644
--- a/src/Minecraft-Loader/patcher.ts
+++ b/src/Minecraft-Loader/patcher.ts
@@ -5,8 +5,6 @@ import { EventEmitter } from 'events';
import { getPathLibraries, getFileFromJar } from '../utils/Index.js';
-
-
export default class forgePatcher {
options: any;
on: any;
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index d3d98464..2a0a6fc3 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -27,7 +27,7 @@ export default class java {
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
} else if (os.platform() == "darwin") {
- let arch = { x64: "mac-os", arm64: this.options.armEnabledMac ? "mac-os-arm64" : "mac-os" }
+ let arch = { x64: "mac-os", arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" }
version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index 7fb407ab..5877aca2 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -82,7 +82,7 @@ async function getFileFromJar(jar: string, file: string = null, path: string = n
let zip = new admZip(jar);
let entries = zip.getEntries();
- return new Promise(resolve => {
+ return await new Promise(resolve => {
for (let entry of entries) {
if (!entry.isDirectory && !path) {
if (entry.entryName == file) fileReturn = entry.getData();
diff --git a/test/index.js b/test/index.js
index 8981c259..d4eb3fc0 100755
--- a/test/index.js
+++ b/test/index.js
@@ -22,17 +22,18 @@ let mc
}
let opt = {
- url: 'https://launcher.luuxis.fr/files/?instance=hypixel',
+ url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
authenticator: mc,
timeout: 10000,
path: './.Minecraft',
instance: 'Hypixel',
- version: '1.8.9',
+ version: '1.16.5',
detached: false,
+ intelEnabledMac: false,
downloadFileMultiple: 30,
loader: {
- type: 'Forge',
+ type: 'forge',
build: 'latest',
enable: true
},
@@ -92,7 +93,7 @@ let mc
})
launch.on('patch', patch => {
- console.log(patch);
+ //console.log(patch);
});
launch.on('data', (e) => {
From 3c7048484e29c034bf3706983a04960310467b92 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 29 Sep 2023 13:35:52 +0200
Subject: [PATCH 020/185] fix error
---
src/Launch.ts | 80 ++++++++++++++++++++++++++-------------------------
test/index.js | 6 ++--
2 files changed, 44 insertions(+), 42 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index cd972be6..43ff9c51 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -22,9 +22,45 @@ import { isold } from './utils/Index.js';
import Downloader from './utils/Downloader.js';
+type loader = {
+ type?: string,
+ build?: string,
+ enable?: boolean
+}
+
+type screen = {
+ width?: number,
+ height?: number,
+ fullscreen?: boolean
+}
+
+type memory = {
+ min?: string,
+ max?: string
+}
+
+type LaunchOPTS = {
+ url: string | null,
+ authenticator: any,
+ timeout: number,
+ path: string,
+ version: string,
+ instance: string,
+ detached: boolean,
+ downloadFileMultiple: number,
+ intelEnabledMac: boolean,
+ loader: loader,
+ verify: boolean,
+ ignored: string[],
+ JVM_ARGS: string[],
+ GAME_ARGS: string[],
+ javaPath: string,
+ screen: screen,
+ memory: memory
+};
export default class Launch {
- options: any;
+ options: LaunchOPTS;
on: any;
emit: any;
@@ -33,47 +69,13 @@ export default class Launch {
this.emit = EventEmitter.prototype.emit;
}
- async Launch(opt: any) {
- this.options = {
- url: opt?.url || null,
- authenticator: opt?.authenticator || null,
- timeout: opt?.timeout || 10000,
- path: path.resolve(opt?.path || '.Minecraft').replace(/\\/g, '/'),
- version: opt?.version || 'latest_release',
- instance: opt?.instance || null,
- detached: opt?.detached || false,
- downloadFileMultiple: opt?.downloadFileMultiple || 3,
- intelEnabledMac: opt?.intelEnabledMac ? true : false,
-
- loader: {
- type: opt?.loader?.type?.toLowerCase() || null,
- build: opt?.loader?.build?.toLowerCase() || 'latest',
- enable: opt?.loader?.enable || false,
- },
-
- verify: opt?.verify || false,
- ignored: opt?.ignored || [],
- JVM_ARGS: opt?.JVM_ARGS || [],
- GAME_ARGS: opt?.GAME_ARGS || [],
-
- javaPath: opt?.javaPath || null,
-
- screen: {
- width: opt?.screen?.width || null,
- height: opt?.screen?.height || null,
- fullscreen: opt?.screen?.fullscreen || false,
- },
-
- memory: {
- min: opt?.memory?.min || '1G',
- max: opt?.memory?.max || '2G'
- }
- }
+ async Launch(opt: LaunchOPTS) {
+ this.options = opt;
+ this.options.path = path.resolve(this.options.path)
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 (!this.options.loader.enable) this.options.loader = false;
this.start();
}
@@ -156,7 +158,7 @@ export default class Launch {
await downloader.downloadFileMultiple(filesList, totsize, this.options.downloadFileMultiple, this.options.timeout);
}
- if (this.options.loader) {
+ if (this.options.loader.enable === true) {
let loaderInstall = new loaderMinecraft(this.options)
loaderInstall.on('extract', (extract: any) => {
diff --git a/test/index.js b/test/index.js
index d4eb3fc0..c037843b 100755
--- a/test/index.js
+++ b/test/index.js
@@ -26,10 +26,10 @@ let mc
authenticator: mc,
timeout: 10000,
path: './.Minecraft',
- instance: 'Hypixel',
+ instance: 'PokeMoonX',
version: '1.16.5',
detached: false,
- intelEnabledMac: false,
+ intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
@@ -93,7 +93,7 @@ let mc
})
launch.on('patch', patch => {
- //console.log(patch);
+ console.log(patch);
});
launch.on('data', (e) => {
From eeaedf8324958300c3eccfb02ed2d025436cd587 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 29 Sep 2023 13:36:07 +0200
Subject: [PATCH 021/185] publish 3.7.0
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 5c7a1c3a..79648427 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.6.4",
+ "version": "3.7.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.6.4",
+ "version": "3.7.0",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index ac6f790d..2beea29d 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.6.4",
+ "version": "3.7.0",
"types": "./build/Index.d.ts",
"exports": {
".": {
From 68e26620f5f41e6239dd64beda9b0d5f8d702a40 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 3 Oct 2023 00:35:11 +0200
Subject: [PATCH 022/185] fix error 3.7.0
---
src/Index.ts | 1 -
src/Launch.ts | 61 +++++++++++++++++++++++++++++++++++++++++----------
test/index.js | 12 +++++-----
3 files changed, 56 insertions(+), 18 deletions(-)
diff --git a/src/Index.ts b/src/Index.ts
index cb838cf8..ae6dfd3d 100755
--- a/src/Index.ts
+++ b/src/Index.ts
@@ -8,7 +8,6 @@ import Microsoft from './Authenticator/Microsoft.js';
import * as Mojang from './Authenticator/Mojang.js';
import Status from './StatusServer/status.js';
-
export {
AZauth as AZauth,
Launch as Launch,
diff --git a/src/Launch.ts b/src/Launch.ts
index 43ff9c51..cbc8eb96 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -9,17 +9,14 @@ 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 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 = {
@@ -42,13 +39,13 @@ type memory = {
type LaunchOPTS = {
url: string | null,
authenticator: any,
- timeout: number,
+ timeout?: number,
path: string,
version: string,
- instance: string,
- detached: boolean,
- downloadFileMultiple: number,
- intelEnabledMac: boolean,
+ instance?: string,
+ detached?: boolean,
+ downloadFileMultiple?: number,
+ intelEnabledMac?: boolean,
loader: loader,
verify: boolean,
ignored: string[],
@@ -70,15 +67,57 @@ export default class Launch {
}
async Launch(opt: LaunchOPTS) {
- this.options = opt;
-
- this.options.path = path.resolve(this.options.path)
+ const defaultOptions: LaunchOPTS = {
+ url: null,
+ authenticator: null,
+ timeout: 10000,
+ path: '.Minecraft',
+ version: 'latest_release',
+ instance: null,
+ detached: false,
+ intelEnabledMac: false,
+ downloadFileMultiple: 3,
+
+ loader: {
+ type: null,
+ build: 'latest',
+ enable: false,
+ },
+
+ verify: false,
+ ignored: [],
+ JVM_ARGS: [],
+ GAME_ARGS: [],
+
+ javaPath: null,
+
+ 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.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
this.start();
}
+
async start() {
let data: any = await this.DownloadGame();
if (data.error) return this.emit('error', data);
diff --git a/test/index.js b/test/index.js
index c037843b..9380af6f 100755
--- a/test/index.js
+++ b/test/index.js
@@ -29,11 +29,11 @@ let mc
instance: 'PokeMoonX',
version: '1.16.5',
detached: false,
- intelEnabledMac: true,
+ intelEnabledMac: false,
downloadFileMultiple: 30,
loader: {
- type: 'forge',
+ type: 'Forge',
build: 'latest',
enable: true
},
@@ -56,10 +56,10 @@ let mc
javaPath: null,
- //screen: {
- // width: 1600,
- // height: 900
- //},
+ screen: {
+ width: 1600,
+ height: 900
+ },
memory: {
min: '4G',
From 3635c58c2780dcc9fdf042cacedfc1f7f69d5d4b Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 3 Oct 2023 00:35:29 +0200
Subject: [PATCH 023/185] publish 3.7.1 stable
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 79648427..a5a268ab 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.7.0",
+ "version": "3.7.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.7.0",
+ "version": "3.7.1",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 2beea29d..5fd416c9 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.7.0",
+ "version": "3.7.1",
"types": "./build/Index.d.ts",
"exports": {
".": {
From 670436e2943ba98c51973bf51e650b63f6148fb1 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 3 Oct 2023 20:31:51 +0200
Subject: [PATCH 024/185] fix remove file
---
src/Minecraft/Minecraft-Bundle.ts | 10 +++++-----
src/Minecraft/Minecraft-Libraries.ts | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Minecraft/Minecraft-Bundle.ts b/src/Minecraft/Minecraft-Bundle.ts
index 0286e1bc..dd7af516 100755
--- a/src/Minecraft/Minecraft-Bundle.ts
+++ b/src/Minecraft/Minecraft-Bundle.ts
@@ -17,7 +17,7 @@ export default class MinecraftBundle {
let todownload = [];
for (let file of bundle) {
- if (!file.path) continue;
+ if (!file.path) continue
file.path = path.resolve(this.options.path, file.path).replace(/\\/g, "/");
file.folder = file.path.split("/").slice(0, -1).join("/");
@@ -28,12 +28,12 @@ export default class MinecraftBundle {
}
if (fs.existsSync(file.path)) {
- if (this.options.ignored.find(ignored => ignored == file.path.replaceAll(`${this.options.path}/`, ""))) continue
+ let replaceName = `${this.options.path}/`
+ if (this.options.instance) replaceName = `${this.options.path}/instances/${this.options.instance}/`
+ if (this.options.ignored.find(ignored => ignored == file.path.replaceAll(replaceName, ""))) continue
if (file.sha1) {
- if (await getFileHash(file.path) != file.sha1) {
- todownload.push(file);
- }
+ if (await getFileHash(file.path) != file.sha1) todownload.push(file);
}
} else todownload.push(file);
diff --git a/src/Minecraft/Minecraft-Libraries.ts b/src/Minecraft/Minecraft-Libraries.ts
index 2576ca8a..532b70a2 100755
--- a/src/Minecraft/Minecraft-Libraries.ts
+++ b/src/Minecraft/Minecraft-Libraries.ts
@@ -78,7 +78,7 @@ export default class Libraries {
sha1: asset.hash,
size: asset.size,
type: path.split("/")[0],
- path: this.options.instance ? `${this.options.path}/instances/${this.options.instance}/${path}` : path,
+ path: this.options.instance ? `instances/${this.options.instance}/${path}` : path,
url: asset.url
});
}
From c76be2ff02370c10a69b64a5d5d4150d86362aea Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 3 Oct 2023 20:32:14 +0200
Subject: [PATCH 025/185] fix arg
---
src/Launch.ts | 2 +-
src/Minecraft/Minecraft-Arguments.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index cbc8eb96..d346d4ee 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -76,7 +76,7 @@ export default class Launch {
instance: null,
detached: false,
intelEnabledMac: false,
- downloadFileMultiple: 3,
+ downloadFileMultiple: 5,
loader: {
type: null,
diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts
index 79613a31..3f5b7f6b 100755
--- a/src/Minecraft/Minecraft-Arguments.ts
+++ b/src/Minecraft/Minecraft-Arguments.ts
@@ -43,7 +43,7 @@ export default class MinecraftArguments {
'${auth_uuid}': this.authenticator.uuid,
'${auth_xuid}': this.authenticator.meta.xuid || this.authenticator.access_token,
'${user_properties}': this.authenticator.user_properties,
- '${user_type}': this.authenticator.meta.type,
+ '${user_type}': this.authenticator.meta.type === 'Xbox' ? 'msa' : this.authenticator.meta.type,
'${version_name}': json.id,
'${assets_index_name}': json.assetIndex.id,
'${game_directory}': this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path,
From 97088f5060ab141b92afd32373e49840507d2a10 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Tue, 3 Oct 2023 20:32:32 +0200
Subject: [PATCH 026/185] publish 3.7.2
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index a5a268ab..8b31a041 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.7.1",
+ "version": "3.7.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.7.1",
+ "version": "3.7.2",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 5fd416c9..35182097 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.7.1",
+ "version": "3.7.2",
"types": "./build/Index.d.ts",
"exports": {
".": {
From bf2697ea22597d103a5f067c597f55c38bccf905 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 28 Oct 2023 22:56:30 +0200
Subject: [PATCH 027/185] fix error
---
package-lock.json | 4 ++--
package.json | 2 +-
src/Minecraft/Minecraft-Arguments.ts | 9 +++++++--
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 8b31a041..63dbcd38 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.7.2",
+ "version": "3.7.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.7.2",
+ "version": "3.7.3",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 35182097..e4f57bbb 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.7.2",
+ "version": "3.7.3",
"types": "./build/Index.d.ts",
"exports": {
".": {
diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts
index 3f5b7f6b..367d0e6d 100755
--- a/src/Minecraft/Minecraft-Arguments.ts
+++ b/src/Minecraft/Minecraft-Arguments.ts
@@ -30,12 +30,17 @@ export default class MinecraftArguments {
async GetGameArguments(json: any, loaderJson: any) {
let game = json.minecraftArguments ? json.minecraftArguments.split(' ') : json.arguments.game;
+ let userType: String
+
if (loaderJson) {
let gameLoader = loaderJson.minecraftArguments ? loaderJson.minecraftArguments.split(' ') : [];
game = game.concat(gameLoader);
- game = game.filter((item: any, index: any, self: any) => index === self.findIndex((res: any) => res == item))
+ game = game.filter((item: String, index: Number, self: any) => index === self.findIndex((res: String) => res == item))
}
+ if (json.id.startsWith('1.16')) userType = 'Xbox'
+ else userType = this.authenticator.meta.type === 'Xbox' ? 'msa' : this.authenticator.meta.type
+
let table = {
'${auth_access_token}': this.authenticator.access_token,
'${auth_session}': this.authenticator.access_token,
@@ -43,7 +48,7 @@ export default class MinecraftArguments {
'${auth_uuid}': this.authenticator.uuid,
'${auth_xuid}': this.authenticator.meta.xuid || this.authenticator.access_token,
'${user_properties}': this.authenticator.user_properties,
- '${user_type}': this.authenticator.meta.type === 'Xbox' ? 'msa' : this.authenticator.meta.type,
+ '${user_type}': userType,
'${version_name}': json.id,
'${assets_index_name}': json.assetIndex.id,
'${game_directory}': this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path,
From d7022cf488f25f21f572c2cd37221b3366f092fc Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 3 Nov 2023 14:53:19 +0100
Subject: [PATCH 028/185] init commit
---
.gitignore | 2 +-
src/Minecraft-Loader/loader/forge/forge.ts | 15 ++++++-----
.../loader/neoForge/neoForge.ts | 2 +-
src/Minecraft/Minecraft-Arguments.ts | 25 ++++++++++++++-----
src/utils/Index.ts | 4 ++-
test/index.js | 18 ++++++-------
6 files changed, 42 insertions(+), 24 deletions(-)
diff --git a/.gitignore b/.gitignore
index 453cb7e9..4b911503 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
node_modules
build
files
-.Minecraft
+Minecraft
test/*.json
webfiles/instances/*
.DS_Store
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index 9afc18ec..241b5279 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -26,7 +26,9 @@ export default class ForgeMC {
async downloadInstaller(Loader: any) {
let metaData = (await nodeFetch(Loader.metaData).then(res => res.json()))[this.options.loader.version];
let AvailableBuilds = metaData;
- let forgeURL = Loader.install
+ let forgeURL: String;
+ let ext: String;
+ let hashFileOrigin: String;
if (!metaData) return { error: `Forge ${this.options.loader.version} not supported` };
let build
@@ -46,13 +48,15 @@ export default class ForgeMC {
metaData = metaData.filter(b => b === build)[0];
if (!metaData) return { error: `Build ${build} not found, Available builds: ${AvailableBuilds.join(', ')}` };
- forgeURL = forgeURL.replace(/\${version}/g, metaData);
+
+ // forgeURL = forgeURL.replace(/\${version}/g, metaData);
let urlMeta = Loader.meta.replace(/\${build}/g, metaData);
- let pathFolder = path.resolve(this.options.path, 'forge');
- let filePath = path.resolve(pathFolder, `forge-${metaData}-installer.jar`);
+ // let pathFolder = path.resolve(this.options.path, 'forge');
+ // let filePath = path.resolve(pathFolder, `forge-${metaData}-installer.jar`);
let meta = await nodeFetch(urlMeta).then(res => res.json());
+ console.log(Object.entries(meta).map(([key, value]) => ({ key, value })));
if (!fs.existsSync(filePath)) {
if (!fs.existsSync(pathFolder)) fs.mkdirSync(pathFolder, { recursive: true });
let downloadForge = new download();
@@ -61,11 +65,10 @@ export default class ForgeMC {
this.emit('progress', downloaded, size, `forge-${metaData}-installer.jar`);
});
- await downloadForge.downloadFile(forgeURL, pathFolder, `forge-${metaData}-installer.jar`);
+ await downloadForge.downloadFile(forgeURL, pathFolder, `forge-${metaData}-installer.${ext}`);
}
let hashFileDownload = await getFileHash(filePath, 'md5');
- let hashFileOrigin = meta?.classifiers?.installer?.jar;
if (hashFileDownload !== hashFileOrigin) {
fs.rmSync(filePath);
diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
index fbf0271a..47710ffb 100644
--- a/src/Minecraft-Loader/loader/neoForge/neoForge.ts
+++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
@@ -3,7 +3,7 @@
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
-import { getPathLibraries, getFileHash, mirrors, getFileFromJar } from '../../../utils/Index.js';
+import { getPathLibraries, mirrors, getFileFromJar } from '../../../utils/Index.js';
import download from '../../../utils/Downloader.js';
import neoForgePatcher from '../../patcher.js'
diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts
index 367d0e6d..88035d9d 100755
--- a/src/Minecraft/Minecraft-Arguments.ts
+++ b/src/Minecraft/Minecraft-Arguments.ts
@@ -3,6 +3,9 @@
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
+import fs from 'fs';
+import os from 'os'
+
import { getPathLibraries, isold } from '../utils/Index.js';
let MojangLib = { win32: "windows", darwin: "osx", linux: "linux" };
@@ -103,6 +106,14 @@ export default class MinecraftArguments {
jvm.push(`-Djava.library.path=${this.options.path}/versions/${json.id}/natives`)
}
+ if (os.platform() == "darwin") {
+ let pathAssets = `${this.options.path}/assets/indexes/${json.assets}.json`;
+ let assets = JSON.parse(fs.readFileSync(pathAssets, 'utf-8'));
+ let icon = assets.objects['icons/minecraft.icns'].hash
+
+ jvm.push(`-Xdock:name=Minecraft`)
+ jvm.push(`-Xdock:icon=${this.options.path}/assets/objects/${icon.substring(0, 2)}/${icon}`)
+ }
jvm.push(...this.options.JVM_ARGS)
return jvm;
@@ -136,11 +147,13 @@ export default class MinecraftArguments {
}
classPath.push(`${this.options.path}/versions/${json.id}/${json.id}.jar`)
- return {classpath:[
- `-cp`,
- classPath.join(process.platform === 'win32' ? ';' : ':'),
-
- ],
- mainClass: loaderJson ? loaderJson.mainClass : json.mainClass}
+ return {
+ classpath: [
+ `-cp`,
+ classPath.join(process.platform === 'win32' ? ';' : ':'),
+
+ ],
+ mainClass: loaderJson ? loaderJson.mainClass : json.mainClass
+ }
}
}
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index 5877aca2..68dcbfbd 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -44,7 +44,9 @@ function loader(type: string) {
metaData: 'https://files.minecraftforge.net/net/minecraftforge/forge/maven-metadata.json',
meta: 'https://files.minecraftforge.net/net/minecraftforge/forge/${build}/meta.json',
promotions: 'https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json',
- install: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-installer.jar'
+ install: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-installer',
+ universal: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-universal',
+ client: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-client',
}
} else if (type === 'neoforge') {
return {
diff --git a/test/index.js b/test/index.js
index 9380af6f..c33b714f 100755
--- a/test/index.js
+++ b/test/index.js
@@ -1,4 +1,4 @@
-const { Microsoft, Launch } = require('../build/Index');
+const { Microsoft, Launch, Mojang } = require('../build/Index');
const launch = new Launch();
const fs = require('fs');
@@ -22,23 +22,23 @@ let mc
}
let opt = {
- url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
+ // url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
authenticator: mc,
timeout: 10000,
- path: './.Minecraft',
- instance: 'PokeMoonX',
- version: '1.16.5',
+ path: './Minecraft',
+ // instance: 'PokeMoonX',
+ version: '1.2.5',
detached: false,
- intelEnabledMac: false,
+ intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
- type: 'Forge',
+ type: 'forge',
build: 'latest',
enable: true
},
- verify: true,
+ verify: false,
ignored: [
'config',
'essential',
@@ -57,7 +57,7 @@ let mc
javaPath: null,
screen: {
- width: 1600,
+ width: 1500,
height: 900
},
From fae56da9165ebc45a8b17095fa908edf06b95dbd Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 3 Nov 2023 18:10:57 +0100
Subject: [PATCH 029/185] test
---
src/Launch.ts | 3 +-
src/Minecraft-Loader/index.ts | 39 +++++++++++---------
src/Minecraft-Loader/loader/forge/forge.ts | 43 ++++++++++++++++------
src/Minecraft/Minecraft-Loader.ts | 3 +-
4 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index d346d4ee..90814799 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -220,7 +220,8 @@ export default class Launch {
.then((data: any) => data)
.catch((err: any) => err);
if (jsonLoader.error) return jsonLoader;
- loaderJson = jsonLoader;
+ if (jsonLoader.ext === 'zip') loaderJson = json;
+ else loaderJson = jsonLoader;
}
if (this.options.verify) await bundle.checkFiles([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]);
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
index 14cca954..6079e365 100644
--- a/src/Minecraft-Loader/index.ts
+++ b/src/Minecraft-Loader/index.ts
@@ -57,7 +57,6 @@ export default class Loader {
async forge(Loader: any) {
let forge = new Forge(this.options);
-
// set event
forge.on('check', (progress, size, element) => {
this.emit('check', progress, size, element);
@@ -79,26 +78,32 @@ export default class Loader {
let installer = await forge.downloadInstaller(Loader);
if (installer.error) return installer;
- // extract install profile
- let profile: any = await forge.extractProfile(installer.filePath);
- if (profile.error) return profile
- let destination = path.resolve(this.options.path, 'versions', profile.version.id)
- if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
- fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
+ if (installer.ext == 'jar') {
+ // extract install profile
+ let profile: any = await forge.extractProfile(installer.filePath);
+ if (profile.error) return profile
+ let destination = path.resolve(this.options.path, 'versions', profile.version.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
- // extract universal jar
- let universal: any = await forge.extractUniversalJar(profile.install, installer.filePath);
- if (universal.error) return universal;
+ // extract universal jar
+ let universal: any = await forge.extractUniversalJar(profile.install, installer.filePath);
+ if (universal.error) return universal;
- // download libraries
- let libraries: any = await forge.downloadLibraries(profile, universal);
- if (libraries.error) return libraries;
+ // download libraries
+ let libraries: any = await forge.downloadLibraries(profile, universal);
+ if (libraries.error) return libraries;
- // patch forge if nessary
- let patch: any = await forge.patchForge(profile.install);
- if (patch.error) return patch;
+ // patch forge if nessary
+ let patch: any = await forge.patchForge(profile.install);
+ if (patch.error) return patch;
- return profile.version;
+ return profile.version;
+ } else {
+ await forge.createJar(installer.filePath);
+ let profile: any = await forge.createProfile();
+ return profile;
+ }
}
async neoForge(Loader: any) {
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index 241b5279..6c6031b2 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -8,6 +8,7 @@ import download from '../../../utils/Downloader.js';
import forgePatcher from '../../patcher.js'
import nodeFetch from 'node-fetch'
+import AdmZip from 'adm-zip';
import fs from 'fs'
import path from 'path'
import { EventEmitter } from 'events';
@@ -27,7 +28,7 @@ export default class ForgeMC {
let metaData = (await nodeFetch(Loader.metaData).then(res => res.json()))[this.options.loader.version];
let AvailableBuilds = metaData;
let forgeURL: String;
- let ext: String;
+ let ext;
let hashFileOrigin: String;
if (!metaData) return { error: `Forge ${this.options.loader.version} not supported` };
@@ -49,23 +50,37 @@ export default class ForgeMC {
if (!metaData) return { error: `Build ${build} not found, Available builds: ${AvailableBuilds.join(', ')}` };
- // forgeURL = forgeURL.replace(/\${version}/g, metaData);
- let urlMeta = Loader.meta.replace(/\${build}/g, metaData);
+ let meta = await nodeFetch(Loader.meta.replace(/\${build}/g, metaData)).then(res => res.json());
+ let installerType = Object.keys(meta.classifiers).find((key: String) => key == 'installer');
+ let clientType = Object.keys(meta.classifiers).find((key: String) => key == 'client');
+ let universalType = Object.keys(meta.classifiers).find((key: String) => key == 'universal');
+
+ if (installerType) {
+ forgeURL = forgeURL = Loader.install.replace(/\${version}/g, metaData);
+ ext = Object.keys(meta.classifiers.installer)[0];
+ hashFileOrigin = meta.classifiers.installer[ext];
+ } else if (clientType) {
+ forgeURL = Loader.client.replace(/\${version}/g, metaData);
+ ext = Object.keys(meta.classifiers.client)[0];
+ hashFileOrigin = meta.classifiers.client[ext];
+ } else if (universalType) {
+ forgeURL = Loader.universal.replace(/\${version}/g, metaData);
+ ext = Object.keys(meta.classifiers.universal)[0];
+ hashFileOrigin = meta.classifiers.universal[ext];
+ }
- // let pathFolder = path.resolve(this.options.path, 'forge');
- // let filePath = path.resolve(pathFolder, `forge-${metaData}-installer.jar`);
- let meta = await nodeFetch(urlMeta).then(res => res.json());
+ let pathFolder = path.resolve(this.options.path, 'forge');
+ let filePath = path.resolve(pathFolder, (`${forgeURL}.${ext}`).split('/').pop());
- console.log(Object.entries(meta).map(([key, value]) => ({ key, value })));
if (!fs.existsSync(filePath)) {
if (!fs.existsSync(pathFolder)) fs.mkdirSync(pathFolder, { recursive: true });
let downloadForge = new download();
downloadForge.on('progress', (downloaded, size) => {
- this.emit('progress', downloaded, size, `forge-${metaData}-installer.jar`);
+ this.emit('progress', downloaded, size, (`${forgeURL}.${ext}`).split('/').pop());
});
- await downloadForge.downloadFile(forgeURL, pathFolder, `forge-${metaData}-installer.${ext}`);
+ await downloadForge.downloadFile(`${forgeURL}.${ext}`, pathFolder, (`${forgeURL}.${ext}`).split('/').pop());
}
let hashFileDownload = await getFileHash(filePath, 'md5');
@@ -74,7 +89,7 @@ export default class ForgeMC {
fs.rmSync(filePath);
return { error: 'Invalid hash' };
}
- return { filePath, metaData }
+ return { filePath, metaData, ext }
}
async extractProfile(pathInstaller: any) {
@@ -241,7 +256,13 @@ export default class ForgeMC {
await patcher.patcher(profile, config);
}
}
-
return true
}
+
+ async createJar(pathInstaller: any) {
+ console.log(this.options)
+
+ }
+
+ async createProfile() { }
}
\ No newline at end of file
diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts
index a96c7fc2..bbbefaf7 100755
--- a/src/Minecraft/Minecraft-Loader.ts
+++ b/src/Minecraft/Minecraft-Loader.ts
@@ -32,16 +32,17 @@ export default class MinecraftLoader {
}
}
});
+
return await new Promise((resolve, reject) => {
loader.install();
loader.on('json', (json: any) => {
let loaderJson = json;
+ if (json.ext === 'zip') return resolve(loaderJson);
loaderJson.libraries = loaderJson.libraries.map((lib: any) => {
lib.loader = `${this.options.path}/loader/${this.options.loader.type}`;
return lib;
});
-
resolve(loaderJson);
});
From 260712262dcd72c5a238ce9a0c758181e85dc1b1 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 3 Nov 2023 22:11:39 +0100
Subject: [PATCH 030/185] add old forge versions
---
src/Launch.ts | 7 +++--
src/Minecraft-Loader/index.ts | 11 ++++---
src/Minecraft-Loader/loader/forge/forge.ts | 36 ++++++++++++++--------
src/Minecraft/Minecraft-Arguments.ts | 10 ++++--
src/Minecraft/Minecraft-Libraries.ts | 7 ++---
src/Minecraft/Minecraft-Loader.ts | 1 -
src/utils/Index.ts | 22 +++++++++++--
test/index.js | 2 ++
webfiles/php/scandir.php | 3 +-
9 files changed, 69 insertions(+), 30 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 90814799..2d443079 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -47,6 +47,7 @@ type LaunchOPTS = {
downloadFileMultiple?: number,
intelEnabledMac?: boolean,
loader: loader,
+ mcp: any,
verify: boolean,
ignored: string[],
JVM_ARGS: string[],
@@ -84,6 +85,8 @@ export default class Launch {
enable: false,
},
+ mcp: null,
+
verify: false,
ignored: [],
JVM_ARGS: [],
@@ -107,6 +110,7 @@ export default class Launch {
this.options = defaultOptions;
this.options.path = path.resolve(this.options.path).replace(/\\/g, '/');
+ this.options.mcp = this.options.mcp ? path.resolve(`${this.options.path}/${this.options.mcp}`).replace(/\\/g, '/'): null;
if (this.options.loader.type) {
this.options.loader.type = this.options.loader.type.toLowerCase()
this.options.loader.build = this.options.loader.build.toLowerCase()
@@ -220,8 +224,7 @@ export default class Launch {
.then((data: any) => data)
.catch((err: any) => err);
if (jsonLoader.error) return jsonLoader;
- if (jsonLoader.ext === 'zip') loaderJson = json;
- else loaderJson = jsonLoader;
+ loaderJson = jsonLoader;
}
if (this.options.verify) await bundle.checkFiles([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]);
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
index 6079e365..e4c8e334 100644
--- a/src/Minecraft-Loader/index.ts
+++ b/src/Minecraft-Loader/index.ts
@@ -100,8 +100,11 @@ export default class Loader {
return profile.version;
} else {
- await forge.createJar(installer.filePath);
- let profile: any = await forge.createProfile();
+ let profile: any = await forge.createProfile(installer.id,installer.filePath);
+ if (profile.error) return profile
+ let destination = path.resolve(this.options.path, 'versions', profile.id)
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${profile.id}.json`), JSON.stringify(profile, null, 4));
return profile;
}
}
@@ -138,7 +141,7 @@ export default class Loader {
fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
//extract universal jar
- let universal: any = await neoForge.extractUniversalJar(profile.install, installer.filePath);
+ let universal: any = await neoForge.extractUniversalJar(profile.install, installer.filePath, installer.oldAPI);
if (universal.error) return universal;
// download libraries
@@ -146,7 +149,7 @@ export default class Loader {
if (libraries.error) return libraries;
// patch forge if nessary
- let patch: any = await neoForge.patchneoForge(profile.install);
+ let patch: any = await neoForge.patchneoForge(profile.install, installer.oldAPI);
if (patch.error) return patch;
return profile.version;
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index 6c6031b2..3eead53f 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -3,12 +3,11 @@
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
-import { getPathLibraries, getFileHash, mirrors, getFileFromJar } from '../../../utils/Index.js';
+import { getPathLibraries, getFileHash, mirrors, getFileFromJar, createZIP } from '../../../utils/Index.js';
import download from '../../../utils/Downloader.js';
import forgePatcher from '../../patcher.js'
import nodeFetch from 'node-fetch'
-import AdmZip from 'adm-zip';
import fs from 'fs'
import path from 'path'
import { EventEmitter } from 'events';
@@ -28,7 +27,7 @@ export default class ForgeMC {
let metaData = (await nodeFetch(Loader.metaData).then(res => res.json()))[this.options.loader.version];
let AvailableBuilds = metaData;
let forgeURL: String;
- let ext;
+ let ext: String;
let hashFileOrigin: String;
if (!metaData) return { error: `Forge ${this.options.loader.version} not supported` };
@@ -58,15 +57,17 @@ export default class ForgeMC {
if (installerType) {
forgeURL = forgeURL = Loader.install.replace(/\${version}/g, metaData);
ext = Object.keys(meta.classifiers.installer)[0];
- hashFileOrigin = meta.classifiers.installer[ext];
+ hashFileOrigin = meta.classifiers.installer[`${ext}`];
} else if (clientType) {
forgeURL = Loader.client.replace(/\${version}/g, metaData);
ext = Object.keys(meta.classifiers.client)[0];
- hashFileOrigin = meta.classifiers.client[ext];
+ hashFileOrigin = meta.classifiers.client[`${ext}`];
} else if (universalType) {
forgeURL = Loader.universal.replace(/\${version}/g, metaData);
ext = Object.keys(meta.classifiers.universal)[0];
- hashFileOrigin = meta.classifiers.universal[ext];
+ hashFileOrigin = meta.classifiers.universal[`${ext}`];
+ } else {
+ return { error: 'Invalid forge installer' };
}
let pathFolder = path.resolve(this.options.path, 'forge');
@@ -89,7 +90,7 @@ export default class ForgeMC {
fs.rmSync(filePath);
return { error: 'Invalid hash' };
}
- return { filePath, metaData, ext }
+ return { filePath, metaData, ext, id: `forge-${build}` };
}
async extractProfile(pathInstaller: any) {
@@ -259,10 +260,21 @@ export default class ForgeMC {
return true
}
- async createJar(pathInstaller: any) {
- console.log(this.options)
-
- }
+ async createProfile(id: any, pathInstaller: any) {
+ let forgeFiles: any = await getFileFromJar(pathInstaller)
+ let minecraftJar: any = await getFileFromJar(this.options.loader.config.minecraftJar)
+ let data: any = await createZIP([...minecraftJar, ...forgeFiles], 'META-INF');
+
+ let destination = path.resolve(this.options.path, 'versions', id);
- async createProfile() { }
+ let profile = JSON.parse(fs.readFileSync(this.options.loader.config.minecraftJson, 'utf-8'))
+ profile.libraries = [];
+ profile.id = id;
+ profile.isOldForge = true;
+ profile.jarPath = path.resolve(destination, `${id}.jar`);
+
+ if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
+ fs.writeFileSync(path.resolve(destination, `${id}.jar`), data, { mode: 0o777 });
+ return profile
+ }
}
\ No newline at end of file
diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts
index 88035d9d..302af909 100755
--- a/src/Minecraft/Minecraft-Arguments.ts
+++ b/src/Minecraft/Minecraft-Arguments.ts
@@ -101,7 +101,6 @@ export default class MinecraftArguments {
jvm.push(opts[process.platform])
}
-
if (json.nativesList) {
jvm.push(`-Djava.library.path=${this.options.path}/versions/${json.id}/natives`)
}
@@ -145,7 +144,14 @@ export default class MinecraftArguments {
classPath.push(`${this.options.path}/libraries/${path.path}/${path.name}`)
}
}
- classPath.push(`${this.options.path}/versions/${json.id}/${json.id}.jar`)
+
+ if (loaderJson?.isOldForge) {
+ classPath.push(loaderJson?.jarPath)
+ } else if (this.options.mcp) {
+ classPath.push(this.options.mcp)
+ } else {
+ classPath.push(`${this.options.path}/versions/${json.id}/${json.id}.jar`)
+ }
return {
classpath: [
diff --git a/src/Minecraft/Minecraft-Libraries.ts b/src/Minecraft/Minecraft-Libraries.ts
index 532b70a2..5f8e2881 100755
--- a/src/Minecraft/Minecraft-Libraries.ts
+++ b/src/Minecraft/Minecraft-Libraries.ts
@@ -49,13 +49,12 @@ export default class Libraries {
});
}
- let clientjar = this.json.downloads.client;
libraries.push({
- sha1: clientjar.sha1,
- size: clientjar.size,
+ sha1: this.json.downloads.client.sha1,
+ size: this.json.downloads.client.size,
path: `versions/${this.json.id}/${this.json.id}.jar`,
type: "Libraries",
- url: clientjar.url
+ url: this.json.downloads.client.url
});
libraries.push({
diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts
index bbbefaf7..7e5fd4b3 100755
--- a/src/Minecraft/Minecraft-Loader.ts
+++ b/src/Minecraft/Minecraft-Loader.ts
@@ -38,7 +38,6 @@ export default class MinecraftLoader {
loader.on('json', (json: any) => {
let loaderJson = json;
- if (json.ext === 'zip') return resolve(loaderJson);
loaderJson.libraries = loaderJson.libraries.map((lib: any) => {
lib.loader = `${this.options.path}/loader/${this.options.loader.type}`;
return lib;
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index 68dcbfbd..d1d7aaf9 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -50,8 +50,10 @@ function loader(type: string) {
}
} else if (type === 'neoforge') {
return {
- metaData: 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge',
- install: 'https://maven.neoforged.net/net/neoforged/forge/${version}/forge-${version}-installer.jar'
+ legacyMetaData: 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge',
+ metaData: 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge',
+ legacyInstall: 'https://maven.neoforged.net/net/neoforged/forge/${version}/forge-${version}-installer.jar',
+ install: 'https://maven.neoforged.net/net/neoforged/neoforge/${version}/neoforge-${version}-installer.jar'
}
} else if (type === 'fabric') {
return {
@@ -88,6 +90,7 @@ async function getFileFromJar(jar: string, file: string = null, path: string = n
for (let entry of entries) {
if (!entry.isDirectory && !path) {
if (entry.entryName == file) fileReturn = entry.getData();
+ if (!file) fileReturn.push({ name: entry.entryName, data: entry.getData() });
}
if (!entry.isDirectory && entry.entryName.includes(path) && path) {
@@ -98,11 +101,24 @@ async function getFileFromJar(jar: string, file: string = null, path: string = n
});
}
+async function createZIP(files: any, ignored: any = null) {
+ let zip = new admZip();
+
+ return await new Promise(resolve => {
+ for (let entry of files) {
+ if (ignored && entry.name.includes(ignored)) continue;
+ zip.addFile(entry.name, entry.data);
+ }
+ resolve(zip.toBuffer());
+ });
+}
+
export {
getPathLibraries,
isold,
getFileHash,
mirrors,
loader,
- getFileFromJar
+ getFileFromJar,
+ createZIP
};
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index c33b714f..c4d01072 100755
--- a/test/index.js
+++ b/test/index.js
@@ -38,6 +38,8 @@ let mc
enable: true
},
+ mcp: 'mcp/test.jar',
+
verify: false,
ignored: [
'config',
diff --git a/webfiles/php/scandir.php b/webfiles/php/scandir.php
index a26254cf..7312a3c3 100755
--- a/webfiles/php/scandir.php
+++ b/webfiles/php/scandir.php
@@ -22,7 +22,6 @@ function scanFolder($dir) {
$filePath = $dir . '/' . $filename;
if ($filename == "php") continue;
if (is_dir($filePath)) $result[] = $filename;
-
}
return $result;
}
@@ -37,7 +36,7 @@ function dirToArray($dir) {
$url_req = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$url = "http://$_SERVER[HTTP_HOST]$url_req$dir/$path";
- $res[] = array("url" => $url, "size" => $size, "hash" => $hash, "path" => $path);
+ $res[] = array("url" => $url, "size" => $size, "hash" => $hash, "path" => $path);
}
return str_replace("\\", "", json_encode($res));
}
From f5360ad9d7397e430a574b65d9e75fc6d5e66fcb Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 3 Nov 2023 22:12:40 +0100
Subject: [PATCH 031/185] publish alpah test
---
package-lock.json | 4 +--
package.json | 2 +-
src/Minecraft-Loader/index.ts | 2 +-
.../loader/neoForge/neoForge.ts | 35 ++++++++++++-------
src/Minecraft-Loader/patcher.ts | 8 ++---
test/index.js | 8 ++---
6 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 63dbcd38..676ab159 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.7.3",
+ "version": "3.8.0-alpha.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.7.3",
+ "version": "3.8.0-alpha.2",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index e4f57bbb..6f58e596 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.7.3",
+ "version": "3.8.0-alpha.2",
"types": "./build/Index.d.ts",
"exports": {
".": {
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
index e4c8e334..89231a9c 100644
--- a/src/Minecraft-Loader/index.ts
+++ b/src/Minecraft-Loader/index.ts
@@ -138,7 +138,7 @@ export default class Loader {
if (profile.error) return profile
let destination = path.resolve(this.options.path, 'versions', profile.version.id)
if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
- fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
+ fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile, null, 4));
//extract universal jar
let universal: any = await neoForge.extractUniversalJar(profile.install, installer.filePath, installer.oldAPI);
diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
index 47710ffb..1115fec3 100644
--- a/src/Minecraft-Loader/loader/neoForge/neoForge.ts
+++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
@@ -24,11 +24,20 @@ export default class NeoForgeMC {
}
async downloadInstaller(Loader: any) {
- let build: string
- let neoForgeURL = Loader.install
+ let build: string;
+ let neoForgeURL: string;
+ let oldAPI: boolean = true;
+ let legacyMetaData = await nodeFetch(Loader.legacyMetaData).then(res => res.json());
let metaData = await nodeFetch(Loader.metaData).then(res => res.json());
- let versions = metaData.versions.filter(version => version.includes(`${this.options.loader.version}-`));
+ let versions = legacyMetaData.versions.filter(version => version.includes(`${this.options.loader.version}-`));
+
+ if (!versions.length) {
+ let minecraftVersion = `${this.options.loader.version.split('.')[1]}.${this.options.loader.version.split('.')[2]}`;
+ versions = metaData.versions.filter(version => version.startsWith(minecraftVersion));
+ oldAPI = false;
+ }
+
if (!versions.length) return { error: `NeoForge doesn't support Minecraft ${this.options.loader.version}` };
if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') {
@@ -37,24 +46,24 @@ export default class NeoForgeMC {
if (!build) return { error: `NeoForge Loader ${this.options.loader.build} not found, Available builds: ${versions.join(', ')}` };
- neoForgeURL = neoForgeURL.replaceAll(/\${version}/g, build);
-
+ if (oldAPI) neoForgeURL = Loader.legacyInstall.replaceAll(/\${version}/g, build);
+ else neoForgeURL = Loader.install.replaceAll(/\${version}/g, build);
let pathFolder = path.resolve(this.options.path, 'neoForge');
- let filePath = path.resolve(pathFolder, `forge-${build}-installer.jar`);
+ let filePath = path.resolve(pathFolder, `neoForge-${build}-installer.jar`);
if (!fs.existsSync(filePath)) {
if (!fs.existsSync(pathFolder)) fs.mkdirSync(pathFolder, { recursive: true });
let downloadForge = new download();
downloadForge.on('progress', (downloaded, size) => {
- this.emit('progress', downloaded, size, `forge-${build}-installer.jar`);
+ this.emit('progress', downloaded, size, `neoForge-${build}-installer.jar`);
});
- await downloadForge.downloadFile(neoForgeURL, pathFolder, `forge-${build}-installer.jar`);
+ await downloadForge.downloadFile(neoForgeURL, pathFolder, `neoForge-${build}-installer.jar`);
}
- return { filePath };
+ return { filePath, oldAPI };
}
async extractProfile(pathInstaller: any) {
@@ -76,7 +85,7 @@ export default class NeoForgeMC {
return neoForgeJSON;
}
- async extractUniversalJar(profile: any, pathInstaller: any) {
+ async extractUniversalJar(profile: any, pathInstaller: any, oldAPI: any) {
let skipneoForgeFilter = true
if (profile.filePath) {
@@ -108,7 +117,7 @@ export default class NeoForgeMC {
if (profile.processors?.length) {
let universalPath = profile.libraries.find(v => {
- return (v.name || '').startsWith('net.neoforged:forge')
+ return (v.name || '').startsWith(oldAPI ? 'net.neoforged:forge' : 'net.neoforged:neoforge')
})
let client: any = await getFileFromJar(pathInstaller, 'data/client.lzma');
@@ -198,7 +207,7 @@ export default class NeoForgeMC {
return libraries
}
- async patchneoForge(profile: any) {
+ async patchneoForge(profile: any, oldAPI: any) {
if (profile?.processors?.length) {
let patcher: any = new neoForgePatcher(this.options);
let config: any = {}
@@ -218,7 +227,7 @@ export default class NeoForgeMC {
minecraftJson: this.options.loader.config.minecraftJson
}
- await patcher.patcher(profile, config);
+ await patcher.patcher(profile, config, oldAPI);
}
}
return true
diff --git a/src/Minecraft-Loader/patcher.ts b/src/Minecraft-Loader/patcher.ts
index bc9452de..2d8f3e94 100644
--- a/src/Minecraft-Loader/patcher.ts
+++ b/src/Minecraft-Loader/patcher.ts
@@ -16,7 +16,7 @@ export default class forgePatcher {
this.emit = EventEmitter.prototype.emit;
}
- async patcher(profile: any, config: any) {
+ async patcher(profile: any, config: any, neoForgeOld: boolean = true) {
let { processors } = profile;
for (let key in processors) {
@@ -29,7 +29,7 @@ export default class forgePatcher {
let jar = getPathLibraries(processor.jar)
let filePath = path.resolve(this.options.path, 'libraries', jar.path, jar.name)
- let args = processor.args.map(arg => this.setArgument(arg, profile, config)).map(arg => this.computePath(arg));
+ let args = processor.args.map(arg => this.setArgument(arg, profile, config, neoForgeOld)).map(arg => this.computePath(arg));
let classPaths = processor.classpath.map(cp => {
let classPath = getPathLibraries(cp)
return `"${path.join(this.options.path, 'libraries', `${classPath.path}/${classPath.name}`)}"`
@@ -97,11 +97,11 @@ export default class forgePatcher {
return true;
}
- setArgument(arg: any, profile: any, config: any) {
+ setArgument(arg: any, profile: any, config: any, neoForgeOld) {
let finalArg = arg.replace('{', '').replace('}', '');
let universalPath = profile.libraries.find(v => {
if (this.options.loader.type === 'forge') return (v.name || '').startsWith('net.minecraftforge:forge')
- if (this.options.loader.type === 'neoforge') return (v.name || '').startsWith('net.neoforged:forge')
+ if (this.options.loader.type === 'neoforge') return (v.name || '').startsWith(neoForgeOld ? 'net.neoforged:forge' : 'net.neoforged:neoforge')
})
if (profile.data[finalArg]) {
diff --git a/test/index.js b/test/index.js
index c4d01072..a3e6192e 100755
--- a/test/index.js
+++ b/test/index.js
@@ -26,16 +26,16 @@ let mc
authenticator: mc,
timeout: 10000,
path: './Minecraft',
- // instance: 'PokeMoonX',
- version: '1.2.5',
+ instance: 'PokeMoonX',
+ version: '1.20.1',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
- type: 'forge',
+ type: 'neoforge',
build: 'latest',
- enable: true
+ enable: false
},
mcp: 'mcp/test.jar',
From a52b46af28b5a6f802b36f7ed2ce61cbb322822b Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Fri, 3 Nov 2023 22:32:30 +0100
Subject: [PATCH 032/185] Update index.js
---
test/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/index.js b/test/index.js
index a3e6192e..1d6ee4db 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,7 +27,7 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.20.1',
+ version: '1.8.8',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
From f31dbf90c7a9db0d15a71579d3b115d287504988 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 4 Nov 2023 13:02:21 +0100
Subject: [PATCH 033/185] publish stable 3.8.1
---
package-lock.json | 4 ++--
package.json | 2 +-
src/Minecraft-Loader/loader/forge/forge.ts | 20 ++++++++++++-----
src/utils/Index.ts | 26 ++++++++++++++++++++--
test/index.js | 8 +++----
5 files changed, 45 insertions(+), 15 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 676ab159..948e3d9d 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.8.0-alpha.2",
+ "version": "3.8.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.8.0-alpha.2",
+ "version": "3.8.1",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index 6f58e596..c1c95fa9 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.8.0-alpha.2",
+ "version": "3.8.1",
"types": "./build/Index.d.ts",
"exports": {
".": {
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index 3eead53f..58336104 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -11,6 +11,9 @@ import nodeFetch from 'node-fetch'
import fs from 'fs'
import path from 'path'
import { EventEmitter } from 'events';
+import { skipLibrary } from '../../../utils/Index.js';
+
+let Lib = { win32: "windows", darwin: "osx", linux: "linux" };
export default class ForgeMC {
options: any;
@@ -176,24 +179,31 @@ export default class ForgeMC {
]
for (let lib of libraries) {
+ let natives = null;
+
if (skipForgeFilter && skipForge.find(libs => lib.name.includes(libs))) {
this.emit('check', check++, libraries.length, 'libraries');
continue;
}
- if (lib.rules) {
+
+ if (skipLibrary(lib)) {
this.emit('check', check++, libraries.length, 'libraries');
continue;
}
+
+ if (lib.natives) {
+ natives = lib.natives[Lib[process.platform]];
+ }
+
let file = {}
- let libInfo = getPathLibraries(lib.name);
+ let libInfo = getPathLibraries(lib.name, natives ? `-${natives}` : '');
let pathLib = path.resolve(this.options.path, 'libraries', libInfo.path);
let pathLibFile = path.resolve(pathLib, libInfo.name);
if (!fs.existsSync(pathLibFile)) {
let url
- let sizeFile = 0
-
- let baseURL = `${libInfo.path}/${libInfo.name}`;
+ let sizeFile = 0;
+ let baseURL = natives ? `${libInfo.path}/` : `${libInfo.path}/${libInfo.name}`;
let response: any = await downloader.checkMirror(baseURL, mirrors)
if (response?.status === 200) {
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index d1d7aaf9..125116f8 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -78,7 +78,8 @@ let mirrors = [
"https://maven.minecraftforge.net",
"https://maven.neoforged.net/releases",
"https://maven.creeperhost.net",
- "https://libraries.minecraft.net"
+ "https://libraries.minecraft.net",
+ "https://repo1.maven.org/maven2"
]
async function getFileFromJar(jar: string, file: string = null, path: string = null) {
@@ -113,6 +114,26 @@ async function createZIP(files: any, ignored: any = null) {
});
}
+function skipLibrary(lib) {
+ let Lib = { win32: "windows", darwin: "osx", linux: "linux" };
+
+ let skip = false;
+ if (lib.rules) {
+ skip = true;
+ lib.rules.forEach(({ action, os, features }) => {
+ if (features) return true;
+ if (action === 'allow' && ((os && os.name === Lib[process.platform]) || !os)) {
+ skip = false;
+ }
+
+ if (action === 'disallow' && ((os && os.name === Lib[process.platform]) || !os)) {
+ skip = true;
+ }
+ });
+ }
+ return skip;
+ }
+
export {
getPathLibraries,
isold,
@@ -120,5 +141,6 @@ export {
mirrors,
loader,
getFileFromJar,
- createZIP
+ createZIP,
+ skipLibrary
};
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 1d6ee4db..27ea949e 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,19 +27,17 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.8.8',
+ version: '1.6.4',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
- type: 'neoforge',
+ type: 'forge',
build: 'latest',
- enable: false
+ enable: true
},
- mcp: 'mcp/test.jar',
-
verify: false,
ignored: [
'config',
From 7ec019b0c7158ff10ad773c619ed17648326c8ee Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Sat, 18 Nov 2023 14:15:59 +0100
Subject: [PATCH 034/185] test
---
src/Launch.ts | 9 +++++++--
src/Minecraft-Loader/index.ts | 2 +-
test/index.js | 14 +++++++-------
3 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 2d443079..89571a15 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -108,13 +108,18 @@ export default class Launch {
};
this.options = defaultOptions;
-
this.options.path = path.resolve(this.options.path).replace(/\\/g, '/');
- this.options.mcp = this.options.mcp ? path.resolve(`${this.options.path}/${this.options.mcp}`).replace(/\\/g, '/'): null;
+
+ 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
diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts
index 89231a9c..e4c8e334 100644
--- a/src/Minecraft-Loader/index.ts
+++ b/src/Minecraft-Loader/index.ts
@@ -138,7 +138,7 @@ export default class Loader {
if (profile.error) return profile
let destination = path.resolve(this.options.path, 'versions', profile.version.id)
if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true });
- fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile, null, 4));
+ fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4));
//extract universal jar
let universal: any = await neoForge.extractUniversalJar(profile.install, installer.filePath, installer.oldAPI);
diff --git a/test/index.js b/test/index.js
index 27ea949e..805e59a0 100755
--- a/test/index.js
+++ b/test/index.js
@@ -22,7 +22,7 @@ let mc
}
let opt = {
- // url: 'http://launcher.luuxis.fr/files?instance=PokeMoonX',
+ // url: 'https://launcher.luuxis.fr/files/?instance=hypixel',
authenticator: mc,
timeout: 10000,
path: './Minecraft',
@@ -35,10 +35,10 @@ let mc
loader: {
type: 'forge',
build: 'latest',
- enable: true
+ enable: true,
},
- verify: false,
+ verify: true,
ignored: [
'config',
'essential',
@@ -56,10 +56,10 @@ let mc
javaPath: null,
- screen: {
- width: 1500,
- height: 900
- },
+ // screen: {
+ // width: 1500,
+ // height: 900
+ // },
memory: {
min: '4G',
From dd77830c10a0b3c449d170ab9fcca7bfd20c2286 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <99091642+Luuxis-tuto@users.noreply.github.com>
Date: Sat, 30 Dec 2023 06:52:19 +0100
Subject: [PATCH 035/185] add windows ARM64
---
src/Minecraft/Minecraft-Java.ts | 12 ++++++++----
test/index.js | 6 +++---
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 2a0a6fc3..911bb6f2 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -16,26 +16,30 @@ export default class java {
async GetJsonJava(jsonversion: any) {
let version: any;
let files: any = [];
+ let archOS: String;
let javaVersionsJson = await nodeFetch("https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json").then(res => res.json())
if (!jsonversion.javaVersion) jsonversion = "jre-legacy"
else jsonversion = jsonversion.javaVersion.component
if (os.platform() == "win32") {
- let arch = { x64: "windows-x64", ia32: "windows-x86" }
+ let arch = { x64: "windows-x64", ia32: "windows-x86", arm64: "windows-arm64" }
version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
+ archOS = arch[os.arch()]
} else if (os.platform() == "darwin") {
- let arch = { x64: "mac-os", arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" }
+ let arch = { x64: "mac-os", arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" }
version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
+ archOS = arch[os.arch()]
} else if (os.platform() == "linux") {
let arch = { x64: "linux", ia32: "linux-i386" }
version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
if (version.includes('undefined')) return { error: true, message: "Java not found" };
javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
+ archOS = arch[os.arch()]
} else return console.log("OS not supported");
if (!javaVersionsJson) return { error: true, message: "Java not found" };
@@ -47,7 +51,7 @@ export default class java {
if (info.type == "directory") continue;
if (!info.downloads) continue;
let file: any = {};
- file.path = `runtime/${version}-${process.platform}/${path.replace(toDelete, "")}`;
+ file.path = `runtime/${version}-${archOS}/${path.replace(toDelete, "")}`;
file.executable = info.executable;
file.sha1 = info.downloads.raw.sha1;
file.size = info.downloads.raw.size;
@@ -57,7 +61,7 @@ export default class java {
}
return {
files: files,
- path: path.resolve(this.options.path, `runtime/${version}-${process.platform}/bin/java${process.platform == "win32" ? ".exe" : ""}`),
+ path: path.resolve(this.options.path, `runtime/${version}-${archOS}/bin/java`),
};
}
diff --git a/test/index.js b/test/index.js
index 805e59a0..49a63a9a 100755
--- a/test/index.js
+++ b/test/index.js
@@ -1,4 +1,4 @@
-const { Microsoft, Launch, Mojang } = require('../build/Index');
+const { Microsoft, Launch } = require('../build/Index');
const launch = new Launch();
const fs = require('fs');
@@ -27,13 +27,13 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.6.4',
+ version: '1.20.4',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
- type: 'forge',
+ type: 'neoforge',
build: 'latest',
enable: true,
},
From 505187cfee84da20af59d415d2e3b614a3f53c26 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Fri, 5 Jan 2024 17:02:43 +0100
Subject: [PATCH 036/185] add rootforge path
---
src/Launch.ts | 2 ++
src/Minecraft/Minecraft-Loader.ts | 11 +++++++----
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 89571a15..dec9bd85 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -20,6 +20,7 @@ import { isold } from './utils/Index.js';
import Downloader from './utils/Downloader.js';
type loader = {
+ rootPath?: boolean,
type?: string,
build?: string,
enable?: boolean
@@ -80,6 +81,7 @@ export default class Launch {
downloadFileMultiple: 5,
loader: {
+ rootPath: false,
type: null,
build: 'latest',
enable: false,
diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts
index 7e5fd4b3..8a6dddc3 100755
--- a/src/Minecraft/Minecraft-Loader.ts
+++ b/src/Minecraft/Minecraft-Loader.ts
@@ -11,15 +11,18 @@ export default class MinecraftLoader {
options: any;
on: any;
emit: any;
+ loaderPath: string;
constructor(options: any) {
this.options = options;
this.on = EventEmitter.prototype.on;
this.emit = EventEmitter.prototype.emit;
+ if (this.options.loader.rootPath) this.loaderPath = this.options.path;
+ else this.loaderPath = `${this.options.path}/loader/${this.options.loader.type}`;
}
async GetLoader(version: any, javaPath: any) {
let loader = new loaderDownloader({
- path: `${this.options.path}/loader/${this.options.loader.type}`,
+ path: this.loaderPath,
downloadFileMultiple: this.options.downloadFileMultiple,
loader: {
type: this.options.loader.type,
@@ -32,14 +35,14 @@ export default class MinecraftLoader {
}
}
});
-
+
return await new Promise((resolve, reject) => {
loader.install();
loader.on('json', (json: any) => {
let loaderJson = json;
loaderJson.libraries = loaderJson.libraries.map((lib: any) => {
- lib.loader = `${this.options.path}/loader/${this.options.loader.type}`;
+ lib.loader = this.loaderPath;
return lib;
});
resolve(loaderJson);
@@ -82,7 +85,7 @@ export default class MinecraftLoader {
if (moddeArguments.jvm) Arguments.jvm = moddeArguments.jvm.map(jvm => {
return jvm
.replace(/\${version_name}/g, version)
- .replace(/\${library_directory}/g, `${this.options.path}/loader/${this.options.loader.type.toLowerCase()}/libraries`)
+ .replace(/\${library_directory}/g, `${this.loaderPath}/libraries`)
.replace(/\${classpath_separator}/g, process.platform === 'win32' ? ';' : ':');
})
From 875b020fa03852ea03316fb51e3f86a93b793ae7 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Fri, 5 Jan 2024 17:03:02 +0100
Subject: [PATCH 037/185] publish 3.8.2
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 948e3d9d..51440f41 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "minecraft-java-core",
- "version": "3.8.1",
+ "version": "3.8.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minecraft-java-core",
- "version": "3.8.1",
+ "version": "3.8.2",
"license": "CCANC",
"dependencies": {
"adm-zip": "^0.5.9",
diff --git a/package.json b/package.json
index c1c95fa9..611de615 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "minecraft-java-core",
- "version": "3.8.1",
+ "version": "3.8.2",
"types": "./build/Index.d.ts",
"exports": {
".": {
From 2bb563c97a153e30dd4aa56b802df1dcb91bd204 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Fri, 5 Jan 2024 17:03:41 +0100
Subject: [PATCH 038/185] fix start forge 1.20.3 > 1.20.4
---
src/Minecraft-Loader/loader/forge/forge.ts | 6 ++++--
src/Minecraft-Loader/loader/neoForge/neoForge.ts | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index 58336104..d5af3feb 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -182,8 +182,10 @@ export default class ForgeMC {
let natives = null;
if (skipForgeFilter && skipForge.find(libs => lib.name.includes(libs))) {
- this.emit('check', check++, libraries.length, 'libraries');
- continue;
+ if (lib.downloads?.artifact?.url == "" || !lib.downloads?.artifact?.url) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
}
if (skipLibrary(lib)) {
diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
index 1115fec3..ca202e70 100644
--- a/src/Minecraft-Loader/loader/neoForge/neoForge.ts
+++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
@@ -150,8 +150,10 @@ export default class NeoForgeMC {
for (let lib of libraries) {
if (skipneoForgeFilter && skipneoForge.find(libs => lib.name.includes(libs))) {
- this.emit('check', check++, libraries.length, 'libraries');
- continue;
+ if (lib.downloads?.artifact?.url == "" || !lib.downloads?.artifact?.url) {
+ this.emit('check', check++, libraries.length, 'libraries');
+ continue;
+ }
}
if (lib.rules) {
this.emit('check', check++, libraries.length, 'libraries');
From 68e55ba86627258dd170af9e0c48265af0dd4b90 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Fri, 5 Jan 2024 17:03:50 +0100
Subject: [PATCH 039/185] Update Minecraft-Arguments.ts
---
src/Minecraft/Minecraft-Arguments.ts | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts
index 302af909..6d0af575 100755
--- a/src/Minecraft/Minecraft-Arguments.ts
+++ b/src/Minecraft/Minecraft-Arguments.ts
@@ -52,7 +52,7 @@ export default class MinecraftArguments {
'${auth_xuid}': this.authenticator.meta.xuid || this.authenticator.access_token,
'${user_properties}': this.authenticator.user_properties,
'${user_type}': userType,
- '${version_name}': json.id,
+ '${version_name}': loaderJson ? loaderJson.id : json.id,
'${assets_index_name}': json.assetIndex.id,
'${game_directory}': this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path,
'${assets_root}': isold(json) ? `${this.options.path}/resources` : `${this.options.path}/assets`,
@@ -94,7 +94,10 @@ export default class MinecraftArguments {
'-XX:G1ReservePercent=20',
'-XX:MaxGCPauseMillis=50',
'-XX:G1HeapRegionSize=32M',
- '-Dfml.ignoreInvalidMinecraftCertificates=true'
+ '-Dfml.ignoreInvalidMinecraftCertificates=true',
+ `-Djna.tmpdir=${this.options.path}/versions/${json.id}/natives`,
+ `-Dorg.lwjgl.system.SharedLibraryExtractPath=${this.options.path}/versions/${json.id}/natives`,
+ `-Dio.netty.native.workdir=${this.options.path}/versions/${json.id}/natives`
]
if (!json.minecraftArguments) {
@@ -147,7 +150,7 @@ export default class MinecraftArguments {
if (loaderJson?.isOldForge) {
classPath.push(loaderJson?.jarPath)
- } else if (this.options.mcp) {
+ } else if (this.options.mcp) {
classPath.push(this.options.mcp)
} else {
classPath.push(`${this.options.path}/versions/${json.id}/${json.id}.jar`)
From 913792f0150c18fae82b6c252e36ddda4d44f270 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Fri, 5 Jan 2024 21:29:23 +0100
Subject: [PATCH 040/185] fix
---
src/Launch.ts | 5 +++--
src/Minecraft-Loader/loader/neoForge/neoForge.ts | 4 ++--
src/Minecraft/Minecraft-Loader.ts | 3 +--
test/index.js | 7 ++++---
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index dec9bd85..6e330b8f 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -20,7 +20,7 @@ import { isold } from './utils/Index.js';
import Downloader from './utils/Downloader.js';
type loader = {
- rootPath?: boolean,
+ path?: string,
type?: string,
build?: string,
enable?: boolean
@@ -81,7 +81,7 @@ export default class Launch {
downloadFileMultiple: 5,
loader: {
- rootPath: false,
+ path: './loader',
type: null,
build: 'latest',
enable: false,
@@ -125,6 +125,7 @@ export default class Launch {
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.start();
}
diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
index ca202e70..17afe3a7 100644
--- a/src/Minecraft-Loader/loader/neoForge/neoForge.ts
+++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
@@ -150,10 +150,10 @@ export default class NeoForgeMC {
for (let lib of libraries) {
if (skipneoForgeFilter && skipneoForge.find(libs => lib.name.includes(libs))) {
- if (lib.downloads?.artifact?.url == "" || !lib.downloads?.artifact?.url) {
+ // if (lib.downloads?.artifact?.url == "" || !lib.downloads?.artifact?.url) {
this.emit('check', check++, libraries.length, 'libraries');
continue;
- }
+ // }
}
if (lib.rules) {
this.emit('check', check++, libraries.length, 'libraries');
diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts
index 8a6dddc3..1cede670 100755
--- a/src/Minecraft/Minecraft-Loader.ts
+++ b/src/Minecraft/Minecraft-Loader.ts
@@ -16,8 +16,7 @@ export default class MinecraftLoader {
this.options = options;
this.on = EventEmitter.prototype.on;
this.emit = EventEmitter.prototype.emit;
- if (this.options.loader.rootPath) this.loaderPath = this.options.path;
- else this.loaderPath = `${this.options.path}/loader/${this.options.loader.type}`;
+ this.loaderPath = `${this.options.path}/${this.options.loader.path}`;
}
async GetLoader(version: any, javaPath: any) {
diff --git a/test/index.js b/test/index.js
index 49a63a9a..306afb56 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,15 +27,16 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.20.4',
+ version: '1.20.2',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
+ path: './loader',
type: 'neoforge',
- build: 'latest',
- enable: true,
+ build: '20.2.86',
+ enable: true
},
verify: true,
From b3e71195b1356d1137689cc68359f26d80933850 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 12:13:29 +0100
Subject: [PATCH 041/185] Refactor JavaDownloader to use modern JS features
---
src/Launch.ts | 4 +-
src/Minecraft/Minecraft-Java.ts | 66 ++++++++++++++++-----------------
test/index.js | 4 +-
3 files changed, 35 insertions(+), 39 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 6e330b8f..73d9dcbd 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -125,7 +125,7 @@ export default class Launch {
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'
+ if (typeof this.options.loader.path !== 'string') this.options.loader.path = `./loader/${this.options.loader.type}`;
this.start();
}
@@ -180,7 +180,7 @@ export default class Launch {
let gameLibraries: any = await libraries.Getlibraries(json);
let gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url);
let gameAssets: any = await new assetsMinecraft(this.options).GetAssets(json);
- let gameJava: any = this.options.javaPath ? { files: [] } : await new javaMinecraft(this.options).GetJsonJava(json);
+ let gameJava: any = this.options.javaPath ? { files: [] } : await new javaMinecraft(this.options).getJavaFiles(json);
if (gameJava.error) return gameJava
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 911bb6f2..a0a553e9 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -7,51 +7,47 @@ import os from 'os';
import nodeFetch from 'node-fetch';
import path from 'path';
-export default class java {
+export default class JavaDownloader {
options: any;
+
constructor(options: any) {
this.options = options;
}
- async GetJsonJava(jsonversion: any) {
- let version: any;
- let files: any = [];
- let archOS: String;
- let javaVersionsJson = await nodeFetch("https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json").then(res => res.json())
+ async getJavaFiles(jsonversion: any) {
+ const archMapping = {
+ win32: { x64: 'windows-x64', ia32: 'windows-x86', arm64: 'windows-arm64' },
+ darwin: { x64: 'mac-os', arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" },
+ linux: { x64: 'linux', ia32: 'linux-i386' }
+ };
+
+ const osPlatform = os.platform();
+ const arch = os.arch();
+ const osArchMapping = archMapping[osPlatform];
+ const javaVersion = jsonversion.javaVersion?.component || 'jre-legacy';
+ let files = []
+
+ if (!osArchMapping) return { error: true, message: 'OS not supported' };
- if (!jsonversion.javaVersion) jsonversion = "jre-legacy"
- else jsonversion = jsonversion.javaVersion.component
+ const archOs: any = osArchMapping[arch];
+ const javaVersionsJson = await nodeFetch(`https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json`).then(res => res.json());
- if (os.platform() == "win32") {
- let arch = { x64: "windows-x64", ia32: "windows-x86", arm64: "windows-arm64" }
- version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
- if (version.includes('undefined')) return { error: true, message: "Java not found" };
- javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
- archOS = arch[os.arch()]
- } else if (os.platform() == "darwin") {
- let arch = { x64: "mac-os", arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" }
- version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
- if (version.includes('undefined')) return { error: true, message: "Java not found" };
- javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
- archOS = arch[os.arch()]
- } else if (os.platform() == "linux") {
- let arch = { x64: "linux", ia32: "linux-i386" }
- version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.version?.name}`
- if (version.includes('undefined')) return { error: true, message: "Java not found" };
- javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0]?.manifest?.url).then(res => res.json())).files)
- archOS = arch[os.arch()]
- } else return console.log("OS not supported");
+ const versionName = javaVersionsJson[archOs]?.[javaVersion]?.[0]?.version?.name;
- if (!javaVersionsJson) return { error: true, message: "Java not found" };
+ if (!versionName) return { error: true, message: 'Java not found' };
- let java = javaVersionsJson.find(file => file[0].endsWith(process.platform == "win32" ? "bin/javaw.exe" : "bin/java"))[0];
- let toDelete = java.replace(process.platform == "win32" ? "bin/javaw.exe" : "bin/java", "");
+ const manifestUrl = javaVersionsJson[archOs][javaVersion][0]?.manifest?.url;
+ const manifest = await nodeFetch(manifestUrl).then(res => res.json());
+ const javaFiles: any = Object.entries(manifest.files);
- for (let [path, info] of javaVersionsJson) {
+ const java = javaFiles.find(([path]) => path.endsWith(process.platform === 'win32' ? 'bin/javaw.exe' : 'bin/java'))[0];
+ const toDelete = java.replace(process.platform === 'win32' ? 'bin/javaw.exe' : 'bin/java', '');
+
+ for (let [path, info] of javaFiles) {
if (info.type == "directory") continue;
if (!info.downloads) continue;
let file: any = {};
- file.path = `runtime/${version}-${archOS}/${path.replace(toDelete, "")}`;
+ file.path = `runtime/jre-${versionName}-${archOs}/${path.replace(toDelete, "")}`;
file.executable = info.executable;
file.sha1 = info.downloads.raw.sha1;
file.size = info.downloads.raw.size;
@@ -59,10 +55,10 @@ export default class java {
file.type = "Java";
files.push(file);
}
+
return {
- files: files,
- path: path.resolve(this.options.path, `runtime/${version}-${archOS}/bin/java`),
+ files,
+ path: path.resolve(this.options.path, `runtime/jre-${versionName}-${archOs}/bin/java`),
};
-
}
}
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 306afb56..634bd764 100755
--- a/test/index.js
+++ b/test/index.js
@@ -33,9 +33,9 @@ let mc
downloadFileMultiple: 30,
loader: {
- path: './loader',
+ // path: './loader',
type: 'neoforge',
- build: '20.2.86',
+ build: 'latest',
enable: true
},
From 842027685eee849336f97456a669d26013bc6c66 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 19:01:14 +0100
Subject: [PATCH 042/185] test
---
package-lock.json | 88 +++++++++++++++++++
package.json | 3 +
src/Launch.ts | 8 +-
src/Minecraft-Loader/loader/forge/forge.ts | 18 ++--
.../loader/neoForge/neoForge.ts | 14 +--
src/Minecraft-Loader/patcher.ts | 4 +-
src/Minecraft/Minecraft-Java.ts | 82 ++++++++++++++++-
src/utils/Index.ts | 36 ++++----
test/index.js | 4 +-
9 files changed, 216 insertions(+), 41 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 51440f41..add9512f 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,9 @@
"version": "3.8.2",
"license": "CCANC",
"dependencies": {
+ "7zip-bin": "^5.2.0",
"adm-zip": "^0.5.9",
+ "node-7z": "^3.0.0",
"node-fetch": "^2.6.9",
"prompt": "^1.2.1",
"tslib": "^2.4.1"
@@ -17,6 +19,7 @@
"devDependencies": {
"@types/adm-zip": "^0.5.2",
"@types/node": "^18.11.13",
+ "@types/node-7z": "^2.1.8",
"@types/node-fetch": "^2.6.2",
"rimraf": "^3.0.2",
"typescript": "^4.9.4"
@@ -45,6 +48,15 @@
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==",
"dev": true
},
+ "node_modules/@types/node-7z": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@types/node-7z/-/node-7z-2.1.8.tgz",
+ "integrity": "sha512-VjiU7yEbczNc3EFKN4GJcAUqAMkn92P/92r6ARjMSXEdixunMD9lC79mTX81vKxTlNYXuvCJ7zvnzlDbFTt2Vw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/node-fetch": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
@@ -55,6 +67,11 @@
"form-data": "^3.0.0"
}
},
+ "node_modules/7zip-bin": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz",
+ "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="
+ },
"node_modules/adm-zip": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
@@ -124,6 +141,22 @@
"node": ">=0.4.0"
}
},
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -207,6 +240,31 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash.defaultsdeep": {
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz",
+ "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA=="
+ },
+ "node_modules/lodash.defaultto": {
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaultto/-/lodash.defaultto-4.14.0.tgz",
+ "integrity": "sha512-G6tizqH6rg4P5j32Wy4Z3ZIip7OfG8YWWlPFzUFGcYStH1Ld0l1tWs6NevEQNEDnO1M3NZYjuHuraaFSN5WqeQ=="
+ },
+ "node_modules/lodash.flattendeep": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ=="
+ },
+ "node_modules/lodash.isempty": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
+ "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg=="
+ },
+ "node_modules/lodash.negate": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/lodash.negate/-/lodash.negate-3.0.2.tgz",
+ "integrity": "sha512-JGJYYVslKYC0tRMm/7igfdHulCjoXjoganRNWM8AgS+RXfOvFnPkOveDhPI65F9aAypCX9QEEQoBqWf7Q6uAeA=="
+ },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -240,11 +298,33 @@
"node": "*"
}
},
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
"node_modules/mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
},
+ "node_modules/node-7z": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/node-7z/-/node-7z-3.0.0.tgz",
+ "integrity": "sha512-KIznWSxIkOYO/vOgKQfJEaXd7rgoFYKZbaurainCEdMhYc7V7mRHX+qdf2HgbpQFcdJL/Q6/XOPrDLoBeTfuZA==",
+ "dependencies": {
+ "debug": "^4.3.2",
+ "lodash.defaultsdeep": "^4.6.1",
+ "lodash.defaultto": "^4.14.0",
+ "lodash.flattendeep": "^4.4.0",
+ "lodash.isempty": "^4.4.0",
+ "lodash.negate": "^3.0.2",
+ "normalize-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/node-fetch": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
@@ -264,6 +344,14 @@
}
}
},
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
diff --git a/package.json b/package.json
index 611de615..7e220a6e 100755
--- a/package.json
+++ b/package.json
@@ -31,7 +31,9 @@
"author": "Luuxis",
"license": "CCANC",
"dependencies": {
+ "7zip-bin": "^5.2.0",
"adm-zip": "^0.5.9",
+ "node-7z": "^3.0.0",
"node-fetch": "^2.6.9",
"prompt": "^1.2.1",
"tslib": "^2.4.1"
@@ -39,6 +41,7 @@
"devDependencies": {
"@types/adm-zip": "^0.5.2",
"@types/node": "^18.11.13",
+ "@types/node-7z": "^2.1.8",
"@types/node-fetch": "^2.6.2",
"rimraf": "^3.0.2",
"typescript": "^4.9.4"
diff --git a/src/Launch.ts b/src/Launch.ts
index 73d9dcbd..7019d328 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -176,11 +176,17 @@ export default class Launch {
let libraries = new librariesMinecraft(this.options)
let bundle = new bundleMinecraft(this.options)
+ let java = new javaMinecraft(this.options)
+
+ java.on('progress', (progress: any, size: any, element: any) => {
+ this.emit('progress', progress, size, element);
+ });
let gameLibraries: any = await libraries.Getlibraries(json);
let gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url);
let gameAssets: any = await new assetsMinecraft(this.options).GetAssets(json);
- let gameJava: any = this.options.javaPath ? { files: [] } : await new javaMinecraft(this.options).getJavaFiles(json);
+ let gameJava: any = this.options.javaPath ? { files: [] } : await java.getJavaFiles(json);
+
if (gameJava.error) return gameJava
diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts
index d5af3feb..cd8c2342 100644
--- a/src/Minecraft-Loader/loader/forge/forge.ts
+++ b/src/Minecraft-Loader/loader/forge/forge.ts
@@ -3,7 +3,7 @@
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
-import { getPathLibraries, getFileHash, mirrors, getFileFromJar, createZIP } from '../../../utils/Index.js';
+import { getPathLibraries, getFileHash, mirrors, getFileFromArchive, createZIP } from '../../../utils/Index.js';
import download from '../../../utils/Downloader.js';
import forgePatcher from '../../patcher.js'
@@ -99,7 +99,7 @@ export default class ForgeMC {
async extractProfile(pathInstaller: any) {
let forgeJSON: any = {}
- let file: any = await getFileFromJar(pathInstaller, 'install_profile.json')
+ let file: any = await getFileFromArchive(pathInstaller, 'install_profile.json')
let forgeJsonOrigin = JSON.parse(file);
if (!forgeJsonOrigin) return { error: { message: 'Invalid forge installer' } };
@@ -108,7 +108,7 @@ export default class ForgeMC {
forgeJSON.version = forgeJsonOrigin.versionInfo;
} else {
forgeJSON.install = forgeJsonOrigin;
- let file: any = await getFileFromJar(pathInstaller, path.basename(forgeJSON.install.json))
+ let file: any = await getFileFromArchive(pathInstaller, path.basename(forgeJSON.install.json))
forgeJSON.version = JSON.parse(file);
}
@@ -125,17 +125,17 @@ export default class ForgeMC {
let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
- let file: any = await getFileFromJar(pathInstaller, profile.filePath)
+ let file: any = await getFileFromArchive(pathInstaller, profile.filePath)
fs.writeFileSync(`${pathFileDest}/${fileInfo.name}`, file, { mode: 0o777 })
} else if (profile.path) {
let fileInfo = getPathLibraries(profile.path)
- let listFile: any = await getFileFromJar(pathInstaller, null, `maven/${fileInfo.path}`)
+ let listFile: any = await getFileFromArchive(pathInstaller, null, `maven/${fileInfo.path}`)
await Promise.all(
listFile.map(async (files: any) => {
let fileName = files.split('/')
this.emit('extract', `Extracting ${fileName[fileName.length - 1]}...`);
- let file: any = await getFileFromJar(pathInstaller, files)
+ let file: any = await getFileFromArchive(pathInstaller, files)
let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
fs.writeFileSync(`${pathFileDest}/${fileName[fileName.length - 1]}`, file, { mode: 0o777 })
@@ -150,7 +150,7 @@ export default class ForgeMC {
return (v.name || '').startsWith('net.minecraftforge:forge')
})
- let client: any = await getFileFromJar(pathInstaller, 'data/client.lzma');
+ let client: any = await getFileFromArchive(pathInstaller, 'data/client.lzma');
let fileInfo = getPathLibraries(profile.path || universalPath.name, '-clientdata', '.lzma')
let pathFile = path.resolve(this.options.path, 'libraries', fileInfo.path)
@@ -273,8 +273,8 @@ export default class ForgeMC {
}
async createProfile(id: any, pathInstaller: any) {
- let forgeFiles: any = await getFileFromJar(pathInstaller)
- let minecraftJar: any = await getFileFromJar(this.options.loader.config.minecraftJar)
+ let forgeFiles: any = await getFileFromArchive(pathInstaller)
+ let minecraftJar: any = await getFileFromArchive(this.options.loader.config.minecraftJar)
let data: any = await createZIP([...minecraftJar, ...forgeFiles], 'META-INF');
let destination = path.resolve(this.options.path, 'versions', id);
diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
index 17afe3a7..88f483ce 100644
--- a/src/Minecraft-Loader/loader/neoForge/neoForge.ts
+++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts
@@ -3,7 +3,7 @@
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
-import { getPathLibraries, mirrors, getFileFromJar } from '../../../utils/Index.js';
+import { getPathLibraries, mirrors, getFileFromArchive } from '../../../utils/Index.js';
import download from '../../../utils/Downloader.js';
import neoForgePatcher from '../../patcher.js'
@@ -69,7 +69,7 @@ export default class NeoForgeMC {
async extractProfile(pathInstaller: any) {
let neoForgeJSON: any = {}
- let file: any = await getFileFromJar(pathInstaller, 'install_profile.json')
+ let file: any = await getFileFromArchive(pathInstaller, 'install_profile.json')
let neoForgeJsonOrigin = JSON.parse(file);
if (!neoForgeJsonOrigin) return { error: { message: 'Invalid neoForge installer' } };
@@ -78,7 +78,7 @@ export default class NeoForgeMC {
neoForgeJSON.version = neoForgeJsonOrigin.versionInfo;
} else {
neoForgeJSON.install = neoForgeJsonOrigin;
- let file: any = await getFileFromJar(pathInstaller, path.basename(neoForgeJSON.install.json))
+ let file: any = await getFileFromArchive(pathInstaller, path.basename(neoForgeJSON.install.json))
neoForgeJSON.version = JSON.parse(file);
}
@@ -95,17 +95,17 @@ export default class NeoForgeMC {
let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
- let file: any = await getFileFromJar(pathInstaller, profile.filePath)
+ let file: any = await getFileFromArchive(pathInstaller, profile.filePath)
fs.writeFileSync(`${pathFileDest}/${fileInfo.name}`, file, { mode: 0o777 })
} else if (profile.path) {
let fileInfo = getPathLibraries(profile.path)
- let listFile: any = await getFileFromJar(pathInstaller, null, `maven/${fileInfo.path}`)
+ let listFile: any = await getFileFromArchive(pathInstaller, null, `maven/${fileInfo.path}`)
await Promise.all(
listFile.map(async (files: any) => {
let fileName = files.split('/')
this.emit('extract', `Extracting ${fileName[fileName.length - 1]}...`);
- let file: any = await getFileFromJar(pathInstaller, files)
+ let file: any = await getFileFromArchive(pathInstaller, files)
let pathFileDest = path.resolve(this.options.path, 'libraries', fileInfo.path)
if (!fs.existsSync(pathFileDest)) fs.mkdirSync(pathFileDest, { recursive: true });
fs.writeFileSync(`${pathFileDest}/${fileName[fileName.length - 1]}`, file, { mode: 0o777 })
@@ -120,7 +120,7 @@ export default class NeoForgeMC {
return (v.name || '').startsWith(oldAPI ? 'net.neoforged:forge' : 'net.neoforged:neoforge')
})
- let client: any = await getFileFromJar(pathInstaller, 'data/client.lzma');
+ let client: any = await getFileFromArchive(pathInstaller, 'data/client.lzma');
let fileInfo = getPathLibraries(profile.path || universalPath.name, '-clientdata', '.lzma')
let pathFile = path.resolve(this.options.path, 'libraries', fileInfo.path)
diff --git a/src/Minecraft-Loader/patcher.ts b/src/Minecraft-Loader/patcher.ts
index 2d8f3e94..02baa8f7 100644
--- a/src/Minecraft-Loader/patcher.ts
+++ b/src/Minecraft-Loader/patcher.ts
@@ -3,7 +3,7 @@ import fs from 'fs'
import path from 'path'
import { EventEmitter } from 'events';
-import { getPathLibraries, getFileFromJar } from '../utils/Index.js';
+import { getPathLibraries, getFileFromArchive } from '../utils/Index.js';
export default class forgePatcher {
options: any;
@@ -132,7 +132,7 @@ export default class forgePatcher {
}
async readJarManifest(jarPath: string) {
- let extraction: any = await getFileFromJar(jarPath, 'META-INF/MANIFEST.MF');
+ let extraction: any = await getFileFromArchive(jarPath, 'META-INF/MANIFEST.MF');
if (extraction) return (extraction.toString("utf8")).split('Main-Class: ')[1].split('\r\n')[0];
return null;
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index a0a553e9..fd49c88b 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -6,12 +6,23 @@
import os from 'os';
import nodeFetch from 'node-fetch';
import path from 'path';
+import fs from 'fs';
+import EventEmitter from 'events';
+import Seven from 'node-7z';
+import sevenBin from '7zip-bin'
+
+import { getFileHash } from '../utils/Index.js';
+import downloader from '../utils/Downloader.js';
export default class JavaDownloader {
options: any;
+ on: any;
+ emit: any;
constructor(options: any) {
this.options = options;
+ this.on = EventEmitter.prototype.on;
+ this.emit = EventEmitter.prototype.emit;
}
async getJavaFiles(jsonversion: any) {
@@ -27,14 +38,14 @@ export default class JavaDownloader {
const javaVersion = jsonversion.javaVersion?.component || 'jre-legacy';
let files = []
- if (!osArchMapping) return { error: true, message: 'OS not supported' };
+ if (!osArchMapping) return await this.getJavaFilesArm64(jsonversion);
const archOs: any = osArchMapping[arch];
const javaVersionsJson = await nodeFetch(`https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json`).then(res => res.json());
const versionName = javaVersionsJson[archOs]?.[javaVersion]?.[0]?.version?.name;
- if (!versionName) return { error: true, message: 'Java not found' };
+ if (!versionName) return await this.getJavaFilesArm64(jsonversion);
const manifestUrl = javaVersionsJson[archOs][javaVersion][0]?.manifest?.url;
const manifest = await nodeFetch(manifestUrl).then(res => res.json());
@@ -61,4 +72,71 @@ export default class JavaDownloader {
path: path.resolve(this.options.path, `runtime/jre-${versionName}-${archOs}/bin/java`),
};
}
+
+ async getJavaFilesArm64(jsonversion: any) {
+ const majorVersion = jsonversion.javaVersion?.majorVersion || '8';
+ const javaVersion = `https://api.adoptium.net/v3/assets/latest/${majorVersion}/hotspot`
+ const javaVersionsJson = await nodeFetch(javaVersion).then(res => res.json());
+
+ const java = javaVersionsJson.find((file: any) => {
+ if (file.binary.image_type === 'jre') {
+ if (file.binary.architecture === (os.arch() === 'x64' ? 'x64' : 'aarch64')) {
+ if (file.binary.os === os.platform()) {
+ return true;
+ }
+ }
+ }
+ });
+
+ if (!java) return { error: true, message: "No Java found" };
+
+ const checksum = java.binary.package.checksum;
+ const url = java.binary.package.link;
+ const fileName = java.binary.package.name;
+ const version = java.release_name;
+ const image_type = java.binary.image_type;
+ const pathFolder = path.resolve(this.options.path, `runtime/jre-${majorVersion}`);
+ const filePath = path.resolve(this.options.path, `runtime/jre-${majorVersion}/${fileName}`);
+
+ if (fs.existsSync(filePath)) {
+ if (await getFileHash(filePath, 'sha256') !== checksum) fs.unlinkSync(filePath);
+ }
+
+ if (!fs.existsSync(filePath)) {
+ if (!fs.existsSync(pathFolder)) fs.mkdirSync(pathFolder, { recursive: true });
+ let download = new downloader();
+
+ download.on('progress', (downloaded, size) => {
+ this.emit('progress', downloaded, size, fileName);
+ });
+
+ await download.downloadFile(url, pathFolder, fileName);
+ }
+
+ if (await getFileHash(filePath, 'sha256') !== checksum) return { error: true, message: "Java checksum failed" };
+
+ // extract file tar.
+ await this.tarExtract(filePath, pathFolder);
+ console.log("Java extracted");
+
+ return {
+ files: [],
+ path: `${pathFolder}/${version}-${image_type}/bin/java`,
+ };
+ }
+
+ async tarExtract(archiveFilePath: string, extractionPath: string) {
+ return new Promise((resolve, reject) => {
+ if (process.platform !== 'win32') fs.chmodSync(sevenBin.path7za, '755');
+ const myStream = Seven.extract(archiveFilePath, extractionPath, {
+ $progress: true,
+ $bin: sevenBin.path7za,
+ recursive: true
+ })
+
+ myStream.on('end', () => resolve);
+ myStream.on('progress', (progress: any) => console.log(progress) )
+ myStream.on('error', (err: any) => reject(err));
+ });
+ }
}
\ No newline at end of file
diff --git a/src/utils/Index.ts b/src/utils/Index.ts
index 125116f8..020b6062 100755
--- a/src/utils/Index.ts
+++ b/src/utils/Index.ts
@@ -82,7 +82,7 @@ let mirrors = [
"https://repo1.maven.org/maven2"
]
-async function getFileFromJar(jar: string, file: string = null, path: string = null) {
+async function getFileFromArchive(jar: string, file: string = null, path: string = null) {
let fileReturn: any = []
let zip = new admZip(jar);
let entries = zip.getEntries();
@@ -116,23 +116,23 @@ async function createZIP(files: any, ignored: any = null) {
function skipLibrary(lib) {
let Lib = { win32: "windows", darwin: "osx", linux: "linux" };
-
- let skip = false;
- if (lib.rules) {
- skip = true;
- lib.rules.forEach(({ action, os, features }) => {
- if (features) return true;
- if (action === 'allow' && ((os && os.name === Lib[process.platform]) || !os)) {
- skip = false;
- }
-
- if (action === 'disallow' && ((os && os.name === Lib[process.platform]) || !os)) {
- skip = true;
- }
- });
- }
- return skip;
+
+ let skip = false;
+ if (lib.rules) {
+ skip = true;
+ lib.rules.forEach(({ action, os, features }) => {
+ if (features) return true;
+ if (action === 'allow' && ((os && os.name === Lib[process.platform]) || !os)) {
+ skip = false;
+ }
+
+ if (action === 'disallow' && ((os && os.name === Lib[process.platform]) || !os)) {
+ skip = true;
+ }
+ });
}
+ return skip;
+}
export {
getPathLibraries,
@@ -140,7 +140,7 @@ export {
getFileHash,
mirrors,
loader,
- getFileFromJar,
+ getFileFromArchive,
createZIP,
skipLibrary
};
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 634bd764..b784df1a 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,7 +27,7 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.20.2',
+ version: '1.12.2',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
@@ -36,7 +36,7 @@ let mc
// path: './loader',
type: 'neoforge',
build: 'latest',
- enable: true
+ enable: false
},
verify: true,
From e55549e57036b021a70e9d9ac688fff4667ecd10 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 20:57:31 +0100
Subject: [PATCH 043/185] Add getJavaOther method for alternative Java
retrieval
---
src/Launch.ts | 22 ++++---
src/Minecraft/Minecraft-Java.ts | 103 +++++++++++++++++++-------------
test/index.js | 8 ++-
3 files changed, 81 insertions(+), 52 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index 7019d328..acd1a9ad 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -37,6 +37,11 @@ type memory = {
max?: string
}
+type javaOPTS = {
+ path?: string,
+ version?: number
+}
+
type LaunchOPTS = {
url: string | null,
authenticator: any,
@@ -53,7 +58,7 @@ type LaunchOPTS = {
ignored: string[],
JVM_ARGS: string[],
GAME_ARGS: string[],
- javaPath: string,
+ java: javaOPTS,
screen: screen,
memory: memory
};
@@ -94,7 +99,10 @@ export default class Launch {
JVM_ARGS: [],
GAME_ARGS: [],
- javaPath: null,
+ java: {
+ path: null,
+ version: null
+ },
screen: {
width: null,
@@ -150,7 +158,7 @@ export default class Launch {
...loaderArguments.game
]
- let java: any = this.options.javaPath ? this.options.javaPath : minecraftJava.path;
+ 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 });
@@ -178,14 +186,14 @@ export default class Launch {
let bundle = new bundleMinecraft(this.options)
let 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)
});
let gameLibraries: any = await libraries.Getlibraries(json);
let gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url);
let gameAssets: any = await new assetsMinecraft(this.options).GetAssets(json);
- let gameJava: any = this.options.javaPath ? { files: [] } : await java.getJavaFiles(json);
+ let gameJava: any = this.options.java.path ? { files: [] } : await java.getJavaFiles(json);
if (gameJava.error) return gameJava
@@ -234,7 +242,7 @@ export default class Launch {
this.emit('patch', patch);
});
- let jsonLoader = await loaderInstall.GetLoader(version, this.options.javaPath ? this.options.javaPath : gameJava.path)
+ let 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;
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index fd49c88b..3be6c2d8 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -26,6 +26,7 @@ export default class JavaDownloader {
}
async getJavaFiles(jsonversion: any) {
+ if (this.options.java.version) return await this.getJavaOther(jsonversion,this.options.java.version);
const archMapping = {
win32: { x64: 'windows-x64', ia32: 'windows-x86', arm64: 'windows-arm64' },
darwin: { x64: 'mac-os', arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" },
@@ -38,14 +39,14 @@ export default class JavaDownloader {
const javaVersion = jsonversion.javaVersion?.component || 'jre-legacy';
let files = []
- if (!osArchMapping) return await this.getJavaFilesArm64(jsonversion);
+ if (!osArchMapping) return await this.getJavaOther(jsonversion);
const archOs: any = osArchMapping[arch];
const javaVersionsJson = await nodeFetch(`https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json`).then(res => res.json());
const versionName = javaVersionsJson[archOs]?.[javaVersion]?.[0]?.version?.name;
- if (!versionName) return await this.getJavaFilesArm64(jsonversion);
+ if (!versionName) return await this.getJavaOther(jsonversion);
const manifestUrl = javaVersionsJson[archOs][javaVersion][0]?.manifest?.url;
const manifest = await nodeFetch(manifestUrl).then(res => res.json());
@@ -73,31 +74,52 @@ export default class JavaDownloader {
};
}
- async getJavaFilesArm64(jsonversion: any) {
- const majorVersion = jsonversion.javaVersion?.majorVersion || '8';
- const javaVersion = `https://api.adoptium.net/v3/assets/latest/${majorVersion}/hotspot`
- const javaVersionsJson = await nodeFetch(javaVersion).then(res => res.json());
-
- const java = javaVersionsJson.find((file: any) => {
- if (file.binary.image_type === 'jre') {
- if (file.binary.architecture === (os.arch() === 'x64' ? 'x64' : 'aarch64')) {
- if (file.binary.os === os.platform()) {
- return true;
- }
- }
- }
- });
+ async getJavaOther(jsonversion: any, versionDownload?: any) {
+ const majorVersion = jsonversion.javaVersion?.component || versionDownload ? versionDownload : '8';
+ console.log(majorVersion)
+ const javaVersionURL = `https://api.adoptium.net/v3/assets/latest/${majorVersion}/hotspot`;
+ const javaVersions = await nodeFetch(javaVersionURL).then(res => res.json());
+ const { platform, arch } = this.getPlatformArch();
+
+ const java = javaVersions.find(file =>
+ file.binary.image_type === 'jre' &&
+ file.binary.architecture === arch &&
+ file.binary.os === platform);
if (!java) return { error: true, message: "No Java found" };
- const checksum = java.binary.package.checksum;
- const url = java.binary.package.link;
- const fileName = java.binary.package.name;
- const version = java.release_name;
+ const { checksum, link: url, name: fileName } = java.binary.package;
+ const { release_name: version } = java;
const image_type = java.binary.image_type;
const pathFolder = path.resolve(this.options.path, `runtime/jre-${majorVersion}`);
- const filePath = path.resolve(this.options.path, `runtime/jre-${majorVersion}/${fileName}`);
+ const filePath = path.resolve(pathFolder, fileName);
+
+ await this.verifyAndDownloadFile({ filePath, pathFolder, fileName, url, checksum });
+
+ let javaPath = `${pathFolder}/${version}-${image_type}/bin/java`;
+ if (platform == 'mac') javaPath = `${pathFolder}/${version}-${image_type}/Contents/Home/bin/java`;
+
+ if (!fs.existsSync(javaPath)) {
+ await this.extract(filePath, pathFolder);
+ await this.extract(filePath.replace('.gz', ''), pathFolder);
+ if (fs.existsSync(filePath.replace('.gz', ''))) fs.unlinkSync(filePath.replace('.gz', ''));
+ if (platform !== 'windows') fs.chmodSync(javaPath, 0o755);
+ }
+
+ return {
+ files: [],
+ path: javaPath,
+ };
+ }
+
+ getPlatformArch() {
+ return {
+ platform: { win32: 'windows', darwin: 'mac', linux: 'linux' }[os.platform()],
+ arch: { x64: 'x64', ia32: 'x32', arm64: 'aarch64', arm: 'arm' }[os.arch()]
+ };
+ }
+ async verifyAndDownloadFile({ filePath, pathFolder, fileName, url, checksum }) {
if (fs.existsSync(filePath)) {
if (await getFileHash(filePath, 'sha256') !== checksum) fs.unlinkSync(filePath);
}
@@ -113,30 +135,27 @@ export default class JavaDownloader {
await download.downloadFile(url, pathFolder, fileName);
}
- if (await getFileHash(filePath, 'sha256') !== checksum) return { error: true, message: "Java checksum failed" };
-
- // extract file tar.
- await this.tarExtract(filePath, pathFolder);
- console.log("Java extracted");
-
- return {
- files: [],
- path: `${pathFolder}/${version}-${image_type}/bin/java`,
- };
+ if (await getFileHash(filePath, 'sha256') !== checksum) {
+ return { error: true, message: "Java checksum failed" };
+ }
}
-
- async tarExtract(archiveFilePath: string, extractionPath: string) {
+ extract(filePath, destPath) {
return new Promise((resolve, reject) => {
- if (process.platform !== 'win32') fs.chmodSync(sevenBin.path7za, '755');
- const myStream = Seven.extract(archiveFilePath, extractionPath, {
- $progress: true,
+ const extract = Seven.extractFull(filePath, destPath, {
$bin: sevenBin.path7za,
- recursive: true
+ recursive: true,
+ $progress: true,
+ })
+ extract.on('end', () => {
+ resolve(true)
+ })
+ extract.on('error', (err) => {
+ reject(err)
+ })
+
+ extract.on('progress', (progress) => {
+ if (progress.percent > 0) this.emit('extract', progress.percent);
})
-
- myStream.on('end', () => resolve);
- myStream.on('progress', (progress: any) => console.log(progress) )
- myStream.on('error', (err: any) => reject(err));
- });
+ })
}
}
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index b784df1a..d88dad54 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,13 +27,12 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.12.2',
+ version: '1.20',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
loader: {
- // path: './loader',
type: 'neoforge',
build: 'latest',
enable: false
@@ -55,7 +54,10 @@ let mc
JVM_ARGS: [],
GAME_ARGS: [],
- javaPath: null,
+ java: {
+ // path: 'java',
+ version: null,
+ },
// screen: {
// width: 1500,
From 7b7d3544a8aea6fad6148e5dbbf3ef62c96c0367 Mon Sep 17 00:00:00 2001
From: Luuxis-tuto <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 21:16:55 +0100
Subject: [PATCH 044/185] add type download
---
src/Launch.ts | 10 ++++++++--
src/Minecraft/Minecraft-Java.ts | 11 +++++------
test/index.js | 5 +++--
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/src/Launch.ts b/src/Launch.ts
index acd1a9ad..85d7d81a 100755
--- a/src/Launch.ts
+++ b/src/Launch.ts
@@ -39,7 +39,8 @@ type memory = {
type javaOPTS = {
path?: string,
- version?: number
+ version?: number,
+ type?: string
}
type LaunchOPTS = {
@@ -101,7 +102,8 @@ export default class Launch {
java: {
path: null,
- version: null
+ version: null,
+ type: 'jre',
},
screen: {
@@ -186,6 +188,10 @@ export default class Launch {
let bundle = new bundleMinecraft(this.options)
let 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)
});
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 3be6c2d8..4dfeae02 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -26,7 +26,7 @@ export default class JavaDownloader {
}
async getJavaFiles(jsonversion: any) {
- if (this.options.java.version) return await this.getJavaOther(jsonversion,this.options.java.version);
+ if (this.options.java.version) return await this.getJavaOther(jsonversion, this.options.java.version);
const archMapping = {
win32: { x64: 'windows-x64', ia32: 'windows-x86', arm64: 'windows-arm64' },
darwin: { x64: 'mac-os', arm64: this.options.intelEnabledMac ? "mac-os" : "mac-os-arm64" },
@@ -76,13 +76,12 @@ export default class JavaDownloader {
async getJavaOther(jsonversion: any, versionDownload?: any) {
const majorVersion = jsonversion.javaVersion?.component || versionDownload ? versionDownload : '8';
- console.log(majorVersion)
const javaVersionURL = `https://api.adoptium.net/v3/assets/latest/${majorVersion}/hotspot`;
const javaVersions = await nodeFetch(javaVersionURL).then(res => res.json());
const { platform, arch } = this.getPlatformArch();
const java = javaVersions.find(file =>
- file.binary.image_type === 'jre' &&
+ file.binary.image_type === this.options.java.type &&
file.binary.architecture === arch &&
file.binary.os === platform);
@@ -96,8 +95,8 @@ export default class JavaDownloader {
await this.verifyAndDownloadFile({ filePath, pathFolder, fileName, url, checksum });
- let javaPath = `${pathFolder}/${version}-${image_type}/bin/java`;
- if (platform == 'mac') javaPath = `${pathFolder}/${version}-${image_type}/Contents/Home/bin/java`;
+ let javaPath = `${pathFolder}/${version}${image_type === 'jre' ? '-jre' : ''}/bin/java`;
+ if (platform == 'mac') javaPath = `${pathFolder}/${version}${image_type === 'jre' ? '-jre' : ''}/Contents/Home/bin/java`;
if (!fs.existsSync(javaPath)) {
await this.extract(filePath, pathFolder);
@@ -115,7 +114,7 @@ export default class JavaDownloader {
getPlatformArch() {
return {
platform: { win32: 'windows', darwin: 'mac', linux: 'linux' }[os.platform()],
- arch: { x64: 'x64', ia32: 'x32', arm64: 'aarch64', arm: 'arm' }[os.arch()]
+ arch: { x64: 'x64', ia32: 'x32', arm64: this.options.intelEnabledMac ? "x64" : "aarch64", arm: 'arm' }[os.arch()]
};
}
diff --git a/test/index.js b/test/index.js
index d88dad54..7400e6dd 100755
--- a/test/index.js
+++ b/test/index.js
@@ -27,7 +27,7 @@ let mc
timeout: 10000,
path: './Minecraft',
instance: 'PokeMoonX',
- version: '1.20',
+ version: '1.12.2',
detached: false,
intelEnabledMac: true,
downloadFileMultiple: 30,
@@ -56,7 +56,8 @@ let mc
java: {
// path: 'java',
- version: null,
+ version: 16,
+ type: 'jdk',
},
// screen: {
From 306e43a62969c514b572761798d0dc3bab1fb62f Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 21:29:19 +0100
Subject: [PATCH 045/185] fix error download
---
src/Minecraft/Minecraft-Java.ts | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 4dfeae02..336b3ba1 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -93,7 +93,14 @@ export default class JavaDownloader {
const pathFolder = path.resolve(this.options.path, `runtime/jre-${majorVersion}`);
const filePath = path.resolve(pathFolder, fileName);
- await this.verifyAndDownloadFile({ filePath, pathFolder, fileName, url, checksum });
+ await this.verifyAndDownloadFile({
+ filePath,
+ pathFolder,
+ fileName,
+ url,
+ checksum,
+ pathExtract: `${pathFolder}/${version}${image_type === 'jre' ? '-jre' : ''}`
+ });
let javaPath = `${pathFolder}/${version}${image_type === 'jre' ? '-jre' : ''}/bin/java`;
if (platform == 'mac') javaPath = `${pathFolder}/${version}${image_type === 'jre' ? '-jre' : ''}/Contents/Home/bin/java`;
@@ -113,14 +120,26 @@ export default class JavaDownloader {
getPlatformArch() {
return {
- platform: { win32: 'windows', darwin: 'mac', linux: 'linux' }[os.platform()],
- arch: { x64: 'x64', ia32: 'x32', arm64: this.options.intelEnabledMac ? "x64" : "aarch64", arm: 'arm' }[os.arch()]
+ platform: {
+ win32: 'windows',
+ darwin: 'mac',
+ linux: 'linux'
+ }[os.platform()],
+ arch: {
+ x64: 'x64',
+ ia32: 'x32',
+ arm64: this.options.intelEnabledMac && os.platform() == 'darwin' ? "x64" : "aarch64",
+ arm: 'arm'
+ }[os.arch()]
};
}
- async verifyAndDownloadFile({ filePath, pathFolder, fileName, url, checksum }) {
+ async verifyAndDownloadFile({ filePath, pathFolder, fileName, url, checksum, pathExtract }) {
if (fs.existsSync(filePath)) {
- if (await getFileHash(filePath, 'sha256') !== checksum) fs.unlinkSync(filePath);
+ if (await getFileHash(filePath, 'sha256') !== checksum) {
+ fs.unlinkSync(filePath);
+ fs.rmdirSync(pathExtract, { recursive: true });
+ }
}
if (!fs.existsSync(filePath)) {
@@ -137,7 +156,9 @@ export default class JavaDownloader {
if (await getFileHash(filePath, 'sha256') !== checksum) {
return { error: true, message: "Java checksum failed" };
}
+
}
+
extract(filePath, destPath) {
return new Promise((resolve, reject) => {
const extract = Seven.extractFull(filePath, destPath, {
From cf483d435402a2aeb5c05d45a5170543bb1d3308 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 21:35:12 +0100
Subject: [PATCH 046/185] Update Minecraft-Java.ts
---
src/Minecraft/Minecraft-Java.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts
index 336b3ba1..6b9911fc 100755
--- a/src/Minecraft/Minecraft-Java.ts
+++ b/src/Minecraft/Minecraft-Java.ts
@@ -75,7 +75,7 @@ export default class JavaDownloader {
}
async getJavaOther(jsonversion: any, versionDownload?: any) {
- const majorVersion = jsonversion.javaVersion?.component || versionDownload ? versionDownload : '8';
+ const majorVersion = versionDownload || jsonversion.javaVersion?.majorVersion;
const javaVersionURL = `https://api.adoptium.net/v3/assets/latest/${majorVersion}/hotspot`;
const javaVersions = await nodeFetch(javaVersionURL).then(res => res.json());
const { platform, arch } = this.getPlatformArch();
From 57aa160daa3e95d5a81ab44f9053353606126e9e Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Wed, 17 Jan 2024 21:35:16 +0100
Subject: [PATCH 047/185] Update index.js
---
test/index.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/index.js b/test/index.js
index 7400e6dd..04391758 100755
--- a/test/index.js
+++ b/test/index.js
@@ -55,8 +55,8 @@ let mc
GAME_ARGS: [],
java: {
- // path: 'java',
- version: 16,
+ path: null,
+ version: null,
type: 'jdk',
},
From e35bb2fe2bbf5d6085b4e78d6f1f52c1cb80b7c1 Mon Sep 17 00:00:00 2001
From: andre <61792917+luuxis@users.noreply.github.com>
Date: Thu, 18 Jan 2024 10:52:35 +0100
Subject: [PATCH 048/185] Create meta.zip
---
test/meta.zip | Bin 0 -> 83109 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test/meta.zip
diff --git a/test/meta.zip b/test/meta.zip
new file mode 100644
index 0000000000000000000000000000000000000000..7da4b003d8663fec055fc8884c876414317a10e2
GIT binary patch
literal 83109
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