silver-mc-java-core
Version:
A library starting minecraft game NW.js and Electron.js
234 lines (188 loc) • 9.7 kB
text/typescript
/**
* @author Luuxis
* @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/
*/
import { getPathLibraries, mirrors, getFileFromArchive } 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 extends EventEmitter {
options: any;
constructor(options = {}) {
super();
this.options = options;
}
async downloadInstaller(Loader: any) {
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 = 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] || 0}`;
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') {
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(', ')}` };
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, `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, `neoForge-${build}-installer.jar`);
});
await downloadForge.downloadFile(neoForgeURL, pathFolder, `neoForge-${build}-installer.jar`);
}
return { filePath, oldAPI };
}
async extractProfile(pathInstaller: any) {
let neoForgeJSON: any = {}
let file: any = await getFileFromArchive(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 getFileFromArchive(pathInstaller, path.basename(neoForgeJSON.install.json))
neoForgeJSON.version = JSON.parse(file);
}
return neoForgeJSON;
}
async extractUniversalJar(profile: any, pathInstaller: any, oldAPI: 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 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 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 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 })
})
);
} else {
skipneoForgeFilter = false
}
if (profile.processors?.length) {
let universalPath = profile.libraries.find(v => {
return (v.name || '').startsWith(oldAPI ? 'net.neoforged:forge' : 'net.neoforged:neoforge')
})
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)
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))) {
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');
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, oldAPI: 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, oldAPI);
}
}
return true
}
}