'use strict'; /* * loaders.js – Mod-Loader-Profile auflösen * ---------------------------------------- * Fabric & Quilt liefern über ihre Meta-API ein fertiges Profil-JSON * (mainClass, zusätzliche Libraries als Maven-Koordinaten, Argumente, * inheritsFrom = Vanilla-Version). Das mergen wir beim Start mit der Vanilla-Version. * * Forge & NeoForge liefern KEIN einfaches Profil, sondern einen Installer, * der Prozessoren ausführt und den Client patcht -> deutlich aufwändiger, * daher hier noch als „in Arbeit" gekennzeichnet. */ const UA = 'AeroMC-Launcher/0.5'; const META = { fabric: 'https://meta.fabricmc.net/v2', quilt: 'https://meta.quiltmc.org/v3', }; async function fetchJson(url) { const res = await fetch(url, { headers: { 'User-Agent': UA, Accept: 'application/json' } }); if (!res.ok) throw new Error('HTTP ' + res.status + ' bei ' + url); return res.json(); } async function fetchText(url) { const res = await fetch(url, { headers: { 'User-Agent': UA } }); if (!res.ok) throw new Error('HTTP ' + res.status + ' bei ' + url); return res.text(); } const FORGE_META = 'https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml'; const NEOFORGE_META = 'https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml'; // NeoForge kodiert die MC-Version im Loader-Namen: 1.21.4 -> 21.4.x function neoforgePrefix(mcVersion) { const p = mcVersion.split('.'); return `${p[1]}.${p[2] || '0'}.`; } // "group:artifact:version[:classifier]" -> { relPath, url } function mavenToUrl(base, name) { const parts = name.split(':'); const group = parts[0].replace(/\./g, '/'); const artifact = parts[1]; const version = parts[2]; const classifier = parts[3] ? '-' + parts[3] : ''; const file = `${artifact}-${version}${classifier}.jar`; const relPath = `${group}/${artifact}/${version}/${file}`; const root = (base || 'https://libraries.minecraft.net/').replace(/\/$/, ''); return { relPath, url: `${root}/${relPath}` }; } // verfügbare Loader-Versionen (für die Anzeige/Auswahl) async function listLoaderVersions(loader, mcVersion) { if (loader === 'fabric' || loader === 'quilt') { const list = await fetchJson(`${META[loader]}/versions/loader/${mcVersion}`); return list.map((l) => ({ version: l.loader.version, stable: !!l.loader.stable })); } if (loader === 'forge') { const xml = await fetchText(FORGE_META); const all = [...xml.matchAll(/([^<]+)<\/version>/g)].map((m) => m[1]); const prefix = mcVersion + '-'; const versions = all.filter((v) => v.startsWith(prefix)).map((v) => v.slice(prefix.length)).reverse(); return versions.map((v, i) => ({ version: v, stable: i === 0 })); } if (loader === 'neoforge') { const xml = await fetchText(NEOFORGE_META); const all = [...xml.matchAll(/([^<]+)<\/version>/g)].map((m) => m[1]); const prefix = neoforgePrefix(mcVersion); const versions = all.filter((v) => v.startsWith(prefix)).reverse(); return versions.map((v, i) => ({ version: v, stable: i === 0 && !/beta/i.test(v) })); } return []; } // löst das Profil (mainClass, libraries, arguments) auf async function resolveLoaderProfile(loader, mcVersion, loaderVersion) { if (loader === 'fabric' || loader === 'quilt') { let lv = loaderVersion; if (!lv) { const list = await fetchJson(`${META[loader]}/versions/loader/${mcVersion}`); if (!list.length) throw new Error(`Kein ${loader}-Loader für Minecraft ${mcVersion} verfügbar.`); const stable = list.find((l) => l.loader && l.loader.stable) || list[0]; lv = stable.loader.version; } const profile = await fetchJson(`${META[loader]}/versions/loader/${mcVersion}/${lv}/profile/json`); return { profile, loaderVersion: lv }; } if (loader === 'forge' || loader === 'neoforge') { const e = new Error( `${loader === 'forge' ? 'Forge' : 'NeoForge'}-Installation ist noch in Arbeit ` + '(braucht Installer + Prozessoren). Fabric und Quilt funktionieren bereits vollständig.', ); e.notImplemented = true; throw e; } throw new Error('Unbekannter Loader: ' + loader); } module.exports = { resolveLoaderProfile, listLoaderVersions, mavenToUrl };