| 16 | } |
| 17 | |
| 18 | async doConvert( |
| 19 | inputFiles: FileData[], |
| 20 | inputFormat: FileFormat, |
| 21 | outputFormat: FileFormat |
| 22 | ): Promise<FileData[]> { |
| 23 | const outputFiles: FileData[] = []; |
| 24 | |
| 25 | for (const file of inputFiles) { |
| 26 | const zip = new JSZip(); |
| 27 | const outZip = new JSZip(); |
| 28 | await zip.loadAsync(file.bytes); |
| 29 | |
| 30 | if (inputFormat.internal === "mrpack" && outputFormat.internal === "zip") { |
| 31 | const indexFile = zip.file("modrinth.index.json"); |
| 32 | if (!indexFile) throw new Error("Invalid Modrinth modpack: missing modrinth.index.json"); |
| 33 | const index = JSON.parse(await indexFile.async("text")); |
| 34 | |
| 35 | const overridePromises: Promise<void>[] = []; |
| 36 | zip.forEach((relativePath, zipEntry) => { |
| 37 | if (!zipEntry.dir && relativePath.startsWith("overrides/")) { |
| 38 | overridePromises.push(zipEntry.async("uint8array").then(data => { |
| 39 | outZip.file(relativePath, data); |
| 40 | })); |
| 41 | } |
| 42 | }); |
| 43 | await Promise.all(overridePromises); |
| 44 | |
| 45 | // Download mods |
| 46 | for (const modFile of index.files || []) { |
| 47 | const downloadUrl = modFile.downloads[0]; |
| 48 | if (downloadUrl) { |
| 49 | try { |
| 50 | const res = await fetch(downloadUrl); |
| 51 | if (res.ok) { |
| 52 | const buffer = await res.arrayBuffer(); |
| 53 | // The path in Modrinth is usually 'mods/somemod.jar' etc. |
| 54 | // It should go into 'overrides/' inside the CF zip. |
| 55 | outZip.file(`overrides/${modFile.path}`, new Uint8Array(buffer)); |
| 56 | } else { |
| 57 | console.warn(`Failed to download ${downloadUrl} (status ${res.status})`); |
| 58 | } |
| 59 | } catch (e) { |
| 60 | console.error(`Error downloading ${downloadUrl}`, e); |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | // Construct CF manifest.json |
| 66 | const modLoaders = []; |
| 67 | for (const [loader, version] of Object.entries(index.dependencies || {})) { |
| 68 | if (loader !== "minecraft") { |
| 69 | let cfLoaderId = `${loader}-${version}`; |
| 70 | if (loader === "fabric-loader") cfLoaderId = `fabric-${version}`; |
| 71 | modLoaders.push({ |
| 72 | id: cfLoaderId, |
| 73 | primary: true |
| 74 | }); |
| 75 | } |