From 38c0aeb516e0b6f3d22c618ed0ffbe32071cb453 Mon Sep 17 00:00:00 2001 From: Tianpao Date: Wed, 2 Jul 2025 21:32:24 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9Amodloaer=E5=AE=89=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ml_install/fabric.ts | 19 ++++++ src/ml_install/forge.ts | 124 +++++++++++++++++++++++++++++++++++++ src/ml_install/neoforge.ts | 76 +++++++++++++++++++++++ src/utils/utils.ts | 39 +++++++++++- 4 files changed, 257 insertions(+), 1 deletion(-) diff --git a/src/ml_install/fabric.ts b/src/ml_install/fabric.ts index e69de29..04ef70c 100644 --- a/src/ml_install/fabric.ts +++ b/src/ml_install/fabric.ts @@ -0,0 +1,19 @@ +import cp from "child_process"; +import fsExtra from "fs-extra/esm"; +import got from "got"; +export default async function install( + mcver: string, + fabricver: string, + path: string +) { + const data = ( + await got.get( + `https://maven.fabricmc.net/net/fabricmc/fabric-installer/1.0.1/fabric-installer-1.0.1.jar` + ) + ).rawBody; + fsExtra.outputFileSync(path+"/fabric-installer-1.0.1.jar", data); + cp.execSync( + `java -jar fabric-installer-1.0.1.jar server -mcver ${mcver} -loader ${fabricver}`, + { cwd: path, stdio: "ignore" } + ); +} diff --git a/src/ml_install/forge.ts b/src/ml_install/forge.ts index e69de29..6f089ac 100644 --- a/src/ml_install/forge.ts +++ b/src/ml_install/forge.ts @@ -0,0 +1,124 @@ +import got from "got"; +import fse from "fs-extra"; +import AdmZip from "adm-zip"; +import pMap from "p-map"; +import pRetry from "p-retry"; +import cp from "child_process"; +import { xfastdownload } from "../utils/utils.js"; +import { LOGGER } from "../utils/logger.js"; + +const gotx = got.extend({ + prefixUrl: "https://bmclapi2.bangbang93.com", + headers: { "User-Agent": "DeEarthX V2" }, +}); + +interface mcinfoX { + libraries: Array; + downloads: any; +} + +export default async function install( + minecraftversion: string, + loaderversion: string, + path: string +) { + //instance + const mcinfo = (await gotx + .get(`version/${minecraftversion}/json`) + .json()) as mcinfoX; //获取Minecraft版本JSON + const forgepath = path; + const forgedata = ( + await gotx.get( + `forge/download?mcversion=${minecraftversion}&version=${loaderversion}&category=installer&format=jar` + ) + ).rawBody; + fse.outputFileSync( + `${forgepath}/Forge-${minecraftversion}-${loaderversion}.jar`, + forgedata + ); //下载Installer.jar + LOGGER.info(`下载Forge-${minecraftversion}-${loaderversion}.jar完成!`); + const zip = new AdmZip( + `${forgepath}/Forge-${minecraftversion}-${loaderversion}.jar` + ).getEntries(); + for (let x = 0; x < zip.length; x++) { + //获取ZIP里的version.json信息 + const e = zip[x]; + if (e.entryName == "version.json") { + const fvdata = JSON.parse(e.getData().toString("utf-8")).libraries; + for (let c = 0; c < fvdata.length; c++) { + //下载依赖1 + const t = fvdata[c].downloads.artifact; + await xfastdownload( + `maven${new URL(t.url).pathname}`, + `${forgepath}/libraries/${t.path}`, + 16 + ); + } + } else if (e.entryName == "install_profile.json") { + const json = JSON.parse(e.getData().toString("utf-8")); + const fvdata = json.libraries; + for (let c = 0; c < fvdata.length; c++) { + //下载依赖2 + const t = fvdata[c].downloads.artifact; + await xfastdownload( + `maven${new URL(t.url).pathname}`, + `${forgepath}/libraries/${t.path}`, + 16 + ); + } + //下载MAPPING与MOJMAPS + /*MOJMAPS*/ + await xfastdownload( + new URL(mcinfo.downloads.server_mappings.url).pathname, + `${forgepath}/libraries/${mavenToUrl( + json.data.MOJMAPS.server.replace(/[[\]]/g, ""), + "" + )}` + ); + /*MAPPING*/ + const tmp = `de/oceanlabs/mcp/mcp_config/${minecraftversion}-${json.data.MCP_VERSION.server.replace( + /['"]/g, + "" + )}/mcp_config-${minecraftversion}-${json.data.MCP_VERSION.server.replace( + /['"]/g, + "" + )}.zip`; + await xfastdownload(`maven/${tmp}`, `${forgepath}/libraries/${tmp}`); + LOGGER.info("下载MAPPING与MOJMAPS完成!"); + } + } + LOGGER.info(`下载Forge的libraries完成!`); + for (let d = 0; d < mcinfo.libraries.length; d++) { + const g = mcinfo.libraries[d].downloads.artifact; + await xfastdownload( + `maven${new URL(g.url).pathname}`, + `${forgepath}/libraries/${g.path}`, + 16 + ); + } + LOGGER.info(`下载Minecraft的Maven完成!`); + await xfastdownload( + `version/${minecraftversion}/server`, + `${forgepath}/libraries/net/minecraft/server/${minecraftversion}/server-${minecraftversion}.jar`, + 1 + ); + try { + cp.execSync( + `java -jar Forge-${minecraftversion}-${loaderversion}.jar --installServer`, + { cwd: forgepath, stdio: "ignore" } + ); //执行Forge安装命令 + } catch (e) {} + LOGGER.info("Forge安装完成!!!"); +} + +function mavenToUrl( + coordinate: { split: (arg0: string) => [any, any, any, any] }, + base = "maven" +) { + const [g, a, v, ce] = coordinate.split(":"); + const [c, e = "jar"] = (ce || "").split("@"); + return `${base.replace(/\/$/, "")}/${g.replace( + /\./g, + "/" + )}/${a}/${v}/${a}-${v}${c ? "-" + c : ""}.${e}`; +} diff --git a/src/ml_install/neoforge.ts b/src/ml_install/neoforge.ts index e69de29..c5a4987 100644 --- a/src/ml_install/neoforge.ts +++ b/src/ml_install/neoforge.ts @@ -0,0 +1,76 @@ +import AdmZip from "adm-zip"; +import fsExtra from "fs-extra/esm"; +import gotx from "got"; +import { xfastdownload } from "../utils/utils.js"; +import { LOGGER } from "../utils/logger.js"; +import cp from "child_process"; +const got = gotx.extend({ + prefixUrl: "https://bmclapi2.bangbang93.com", + headers: { "User-Agent": "DeEarthX V2" }, +}); + +interface mcinfoX { + libraries: Array; + downloads: any; +} + +export default async function install( + minecraft: string, + neoforge: string, + path: string +) { + const mcinfo = (await gotx + .get(`version/${minecraft}/json`) + .json()) as mcinfoX; //获取Minecraft版本JSON + const installer = ( + await got.get(`neoforge/version/${neoforge}/download/installer.jar`) + ).rawBody; + fsExtra.outputFileSync(path + `/installer.jar`, installer); + const zip = new AdmZip(path + `/installer.jar`).getEntries(); + for (let i = 0; i < zip.length; i++) { + const e = zip[i]; + if (e.entryName == "version.json") { + const fvdata = JSON.parse(e.getData().toString("utf-8")).libraries; + for (let c = 0; c < fvdata.length; c++) { + //下载依赖1 + const t = fvdata[c].downloads.artifact; + await xfastdownload( + `maven${new URL(t.url).pathname}`, + `${path}/libraries/${t.path}`, + 16 + ); + } + } else if (e.entryName == "install_profile.json") { + const json = JSON.parse(e.getData().toString("utf-8")); + const fvdata = json.libraries; + for (let c = 0; c < fvdata.length; c++) { + //下载依赖2 + const t = fvdata[c].downloads.artifact; + await xfastdownload( + `maven${new URL(t.url).pathname}`, + `${path}/libraries/${t.path}`, + 16 + ); + } + } + } + for (let d = 0; d < mcinfo.libraries.length; d++) { + const g = mcinfo.libraries[d].downloads.artifact; + await xfastdownload( + `maven${new URL(g.url).pathname}`, + `${path}/libraries/${g.path}`, + 16 + ); + } + await xfastdownload( + `version/${minecraft}/server`, + `${path}/libraries/net/minecraft/server/${minecraft}/server-${minecraft}.jar`, + 1 + ); + LOGGER.info("下载NeoForge完成!"); + cp.execSync(`java -jar ${path}/installer.jar --installServer`, { + cwd: path, + stdio: "ignore", + }); + LOGGER.info("安装NeoForge完成!"); +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index cf5ee84..c6c4501 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -82,4 +82,41 @@ export async function mr_fastdownload(data:[string,string,string]){ multibar.remove(bar); } }, { concurrency: 16 }); -} \ No newline at end of file +} + +export async function xfastdownload( + url: string, + path: string, + concurrency: number = 1 + ) { + let e = []; + e.push([url, path]); + await pMap( + e, + async (e) => { + try { + return await pRetry( + async () => { + if ( + url !== null && + url !== "" && + path !== null && + !fse.existsSync(e[1]) + ) { + const res = (await got.get(e[0])).rawBody; //下载文件 + await fse.outputFile(e[1], res); //保存文件 + } + }, + { + retries: 2, + } + ); + } catch (error) { + LOGGER.error({ err: error }); + } + }, + { + concurrency: concurrency, + } + ); + } \ No newline at end of file