UNPKG

dmclc

Version:

Dolphin Minecraft Launcher Core

328 lines (327 loc) 11.6 kB
import fs from "fs"; import got from "got"; import StreamZip from "node-stream-zip"; import { ModInfo } from "../../mods/mod.js"; import { merge } from "../../utils/MergeVersionJSONs.js"; import { transformJSON } from "../../utils/transformJSON.js"; import { SemanticVersionImpl } from "./version/SemanticVersionImpl.js"; import { VersionParser } from "./version/VersionParser.js"; import { VersionPredicateParser } from "./version/VersionPredicateParser.js"; import * as streamPromises from "stream/promises"; let temp = (await import("temp")).track(); export class FabricLikeLoader { intermediaryMaven = "https://maven.fabricmc.net/"; launcher; constructor(launcher) { this.launcher = launcher; } async findModInfos(path) { const zip = new StreamZip.async({ file: path }); try { return this.findModInfosInZip(zip); } finally { await zip.close(); } } async findModInfosInZip(zip) { const entry = await zip.entry("fabric.mod.json"); if (entry === undefined) return []; const result = []; const json = JSON.parse(transformJSON((await zip.entryData(entry)).toString())); if (json.jars !== undefined) { for (const jar of json.jars) { const file = temp.createWriteStream(); streamPromises.pipeline(await zip.stream(jar.file), file); file.close(); result.push(...await this.findModInfos(file.path)); } } const info = new ModInfo(this.name, json, this.launcher); info.data = json; result.push(info); return result; } cachedLoaderVersions = new Map(); /** * * @throws {@link FormattedError} * @param MCVersion - Minecraft version. * @returns Loader versions. */ async getSuitableLoaderVersions(MCVersion) { if (MCVersion.extras.version === "Unknown") { await this.launcher.error("loaders.minecraft_version_unknown"); return []; } const versions = JSON.parse((await got(`${this.metaURL}/versions/loader/${encodeURIComponent(MCVersion.extras.version)}`)).body); const result = []; versions.forEach(v => { this.cachedLoaderVersions.set(`${MCVersion.extras.version}-${v.loader.version}`, v); result.push(v.loader.version); }); return result; } async install(MCVersion, version) { if (MCVersion.extras.version === "Unknown") { await this.launcher.error("loaders.minecraft_version_unknown"); return false; } const versionInfo = this.cachedLoaderVersions.get(`${MCVersion}-${version}`) ?? await got(`${this.metaURL}/versions/loader/${encodeURIComponent(MCVersion.extras.version)}/${encodeURIComponent(version)}`).json(); const mcVersion = JSON.parse(fs.readFileSync(`${this.launcher.rootPath}/versions/${MCVersion.name}/${MCVersion.name}.json`).toString()); if (mcVersion.mainClass === versionInfo.launcherMeta.mainClass.client) return true; const newVersion = await got(`${this.metaURL}/versions/loader/${encodeURIComponent(MCVersion.extras.version)}/${encodeURIComponent(version)}/profile/json`).json(); MCVersion.versionObject = merge(mcVersion, newVersion); fs.writeFileSync(`${MCVersion.versionRoot}/${MCVersion.name}.json`, JSON.stringify(MCVersion.versionObject)); return true; } } /** * See net.fabricmc.loader.impl.game.minecraft.McVersionLookup#normalizeVersion * @param mc - Original Minecraft version. */ export function normalizeVersion(mc) { let matcher; if ((matcher = mc.match(/(.*)_experimental-snapshot-(.*)/))) { return `${matcher[1]}-Experimetal.${matcher[2]}`; } else if ((matcher = mc.match(/(.*)-rc\d+/))) { const release = matcher[1]; let rcBuild = matcher[2]; if (release === "1.16") { const build = parseInt(rcBuild); rcBuild = (build + 8).toString(); } return `${release}-rc.${rcBuild}`; } else if ((matcher = mc.match(/(.*)-pre\d+/))) { const release = matcher[1]; const legacy = VersionPredicateParser.parseOne("<=1.16").test(SemanticVersionImpl.of(release, false)); if (legacy) { return `${release}-rc.${matcher[2]}`; } else return `${release}-beta.${matcher[2]}`; } else if ((matcher = mc.match(/^(\d+)w(\d+)(.)$/))) { return `${getSnapshotTarget(parseInt(matcher[1]), parseInt(matcher[2]))}-alpha.${matcher[1]}.${matcher[2]}.${matcher[3]}`; } else if (mc.includes("combat")) { return getCombatVersion(mc); } else if (mc === "15w14a") { return "1.8.4-alpha.15.14.a+loveandhugs"; } else if (mc.match(/^\d\.\d+(\.\d+)?$/)) { return mc; } else if (mc.startsWith("b1.")) { return `1.0.0-beta.${mc.substring(3)}`; } else if (mc.startsWith("a1.")) { return `1.0.0-alpha.${mc.substring(3)}`; } else if (mc.startsWith("inf-")) { return `0.31.${mc.substring(4)}`; } else if (mc.startsWith("c0.")) { return mc.substring(1); } else if (mc.startsWith("rd-")) { let version = mc.substring(3); if (version === "20090515") version = "150000"; return `0.0.0-rd.${version}`; } else if (mc === "1.RV-Pre1") { return "1.9.2-rv+trendy"; } else if (mc === "3D Shareware v1.34 / 62337d1d00cf4d86a03b975208d8c323") { return "1.14-alpha.19.13.shareware"; } else if (mc === "20w14infinite") { return "1.16-alpha.20.13.inf"; } else return "1.145.14"; } /** * Copied from net.fabricmc.loader.impl.game.minecraft.McVersionLookup#getRelease * Copyright Notice: * Copyright 2016 FabricMC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getSnapshotTarget(year, week) { if (year == 22 && week >= 42 || year >= 23) { return "1.19.3"; } else if (year == 22 && week == 24) { return "1.19.1"; } else if (year == 22 && week >= 11 && week <= 19) { return "1.19"; } else if (year == 22 && week >= 3 && week <= 7) { return "1.18.2"; } else if (year == 21 && week >= 37 && week <= 44) { return "1.18"; } else if (year == 20 && week >= 45 || year == 21 && week <= 20) { return "1.17"; } else if (year == 20 && week >= 27 && week <= 30) { return "1.16.2"; } else if (year == 20 && week >= 6) { return "1.16"; } else if (year == 19 && week >= 34) { return "1.15"; } else if (year == 18 && week >= 43 || year == 19 && week <= 14) { return "1.14"; } else if (year == 18 && week >= 30 && week <= 33) { return "1.13.1"; } else if (year == 17 && week >= 43 || year == 18 && week <= 22) { return "1.13"; } else if (year == 17 && week == 31) { return "1.12.1"; } else if (year == 17 && week >= 6 && week <= 18) { return "1.12"; } else if (year == 16 && week == 50) { return "1.11.1"; } else if (year == 16 && week >= 32 && week <= 44) { return "1.11"; } else if (year == 16 && week >= 20 && week <= 21) { return "1.10"; } else if (year == 16 && week >= 14 && week <= 15) { return "1.9.3"; } else if (year == 15 && week >= 31 || year == 16 && week <= 7) { return "1.9"; } else if (year == 14 && week >= 2 && week <= 34) { return "1.8"; } else if (year == 13 && week >= 47 && week <= 49) { return "1.7.4"; } else if (year == 13 && week >= 36 && week <= 43) { return "1.7.2"; } else if (year == 13 && week >= 16 && week <= 26) { return "1.6"; } else if (year == 13 && week >= 11 && week <= 12) { return "1.5.1"; } else if (year == 13 && week >= 1 && week <= 10) { return "1.5"; } else if (year == 12 && week >= 49 && week <= 50) { return "1.4.6"; } else if (year == 12 && week >= 32 && week <= 42) { return "1.4.2"; } else if (year == 12 && week >= 15 && week <= 30) { return "1.3.1"; } else if (year == 12 && week >= 3 && week <= 8) { return "1.2.1"; } else if (year == 11 && week >= 47 || year == 12 && week <= 1) { return "1.1"; } return ""; } function getCombatVersion(mc) { switch (mc) { case "1.14.3 - Combat Test / 5d5e0be06e714f03bba436c42db4c85b": // The first Combat Test, forked from 1.14.3 Pre-Release 4 return "1.14.3-rc.4.combat.1"; case "1.14_combat-0": // The second Combat Test, forked from 1.14.4 return "1.14.5-combat.2"; case "1.14_combat-3": // The third Combat Test, forked from 1.14.4 return "1.14.5-combat.3"; case "1.15_combat-1": // The fourth Combat Test, forked from 1.15 Pre-release 3 return "1.15-rc.3.combat.4"; case "1.15_combat-6": // The fifth Combat Test, forked from 1.15.2 Pre-release 2 return "1.15.2-rc.2.combat.5"; case "1.16_combat-0": // The sixth Combat Test, forked from 1.16.2 Pre-release 3 return "1.16.2-beta.3.combat.6"; case "1.16_combat-1": // Private testing Combat Test 7, forked from 1.16.2 return "1.16.3-combat.7"; case "1.16_combat-2": // Private testing Combat Test 7b, forked from 1.16.2 return "1.16.3-combat.7.b"; case "1.16_combat-3": // The seventh Combat Test 7c, forked from 1.16.2 return "1.16.3-combat.7.c"; case "1.16_combat-4": // Private testing Combat Test 8(a?), forked from 1.16.2 return "1.16.3-combat.8"; case "1.16_combat-5": // The eighth Combat Test 8b, forked from 1.16.2 return "1.16.3-combat.8.b"; case "1.16_combat-6": // The ninth Combat Test 8c, forked from 1.16.2 return "1.16.3-combat.8.c"; default: return "11.45.14-1919810"; } } export function checkMatch(current, required) { if (current === "Provided") return true; let p; const currentV = VersionParser.parse(current, false); if (required instanceof Array) { p = VersionPredicateParser.parse(required); } else p = new Set([VersionPredicateParser.parseOne(required)]); let res = false; for (const i of p) { res ||= i.test(currentV); } return res; } export function formatDepVersion(version, launcher) { if (version instanceof Array) { return version.map(v => formatDepVersion(v, launcher)).join(` ${launcher.i18n("misc.or")} `); } const v = VersionPredicateParser.parseOne(version); return v.toString(); }