Skip to content

Commit 4fc4eb7

Browse files
committed
fix: Support 1.4.7 forge installation
1 parent 333b718 commit 4fc4eb7

File tree

4 files changed

+116
-10
lines changed

4 files changed

+116
-10
lines changed

packages/core/launch.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ export async function generateArguments(options: LaunchOption) {
674674
natives_directory: nativeRoot,
675675
launcher_name: launcherName,
676676
launcher_version: launcherBrand,
677+
game_directory: gamePath,
677678
classpath: [
678679
...version.libraries.filter((lib) => !lib.isNative).map((lib) => mc.getLibraryByPath(lib.download.path)),
679680
mc.getVersionJar(version.minecraftVersion),
@@ -723,6 +724,7 @@ export async function generateArguments(options: LaunchOption) {
723724
assets_root: assetsDir,
724725
game_assets: join(assetsDir, 'virtual', version.assets),
725726
assets_index_name: version.assets,
727+
auth_session: accessToken,
726728
game_directory: gamePath,
727729
auth_player_name: name,
728730
auth_uuid: id,

packages/installer/forge.ts

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { LibraryInfo, MinecraftFolder, MinecraftLocation, Version as VersionJson } from '@xmcl/core'
22
import { parse as parseForge } from '@xmcl/forge-site-parser'
33
import { Task, task } from '@xmcl/task'
4-
import { filterEntries, open, openEntryReadStream, readEntry } from '@xmcl/unzip'
4+
import { filterEntries, open, openEntryReadStream, readAllEntries, readEntry } from '@xmcl/unzip'
55
import { createWriteStream } from 'fs'
66
import { writeFile } from 'fs/promises'
77
import { dirname, join } from 'path'
88
import { pipeline } from 'stream/promises'
99
import { Dispatcher, request } from 'undici'
1010
import { Entry, ZipFile } from 'yauzl'
11+
import { ZipFile as WriteableZipFile } from 'yazl'
1112
import { DownloadTask } from './downloadTask'
1213
import { LibraryOptions, resolveLibraryDownloadUrls } from './minecraft'
13-
import { installByProfileTask, InstallProfile, InstallProfileOption } from './profile'
14-
import { ensureFile, InstallOptions as InstallOptionsBase, joinUrl, normalizeArray } from './utils'
14+
import { InstallProfile, InstallProfileOption, installByProfileTask } from './profile'
15+
import { InstallOptions as InstallOptionsBase, ensureDir, ensureFile, joinUrl, normalizeArray } from './utils'
1516
import { ZipValidator } from './zipValdiator'
1617

1718
export interface ForgeVersionList {
@@ -144,8 +145,12 @@ export interface InstallForgeOptions extends LibraryOptions, InstallOptionsBase,
144145
export class DownloadForgeInstallerTask extends DownloadTask {
145146
readonly installJarPath: string
146147

147-
constructor(forgeVersion: string, installer: RequiredVersion['installer'], minecraft: MinecraftFolder, options: InstallForgeOptions) {
148-
const path = installer ? installer.path : `net/minecraftforge/forge/${forgeVersion}/forge-${forgeVersion}-installer.jar`
148+
constructor(forgeVersion: string, installer: RequiredVersion['installer'], minecraft: MinecraftFolder, options: InstallForgeOptions, legacy?: boolean) {
149+
const classifier = legacy ? 'universal' : 'installer'
150+
const ext = legacy ? 'zip' : 'jar'
151+
const path = installer
152+
? installer.path
153+
: `net/minecraftforge/forge/${forgeVersion}/forge-${forgeVersion}-${classifier}.${ext}`
149154
let url: string
150155
if (installer) {
151156
try {
@@ -161,11 +166,11 @@ export class DownloadForgeInstallerTask extends DownloadTask {
161166
}
162167

163168
const library = VersionJson.resolveLibrary({
164-
name: `net.minecraftforge:forge:${forgeVersion}:installer`,
169+
name: `net.minecraftforge:forge:${forgeVersion}:${classifier}`,
165170
downloads: {
166171
artifact: {
167172
url,
168-
path: `net/minecraftforge/forge/${forgeVersion}/forge-${forgeVersion}-installer.jar`,
173+
path: `net/minecraftforge/forge/${forgeVersion}/forge-${forgeVersion}-${classifier}.${ext}`,
169174
size: -1,
170175
sha1: installer?.sha1 || '',
171176
},
@@ -206,6 +211,96 @@ function extractEntryTo(zip: ZipFile, e: Entry, dest: string) {
206211
return openEntryReadStream(zip, e).then((stream) => pipeline(stream, createWriteStream(dest)))
207212
}
208213

214+
async function installLegacyForgeFromUniversalZip(forgeZip: ZipFile, mc: MinecraftFolder, forgeVersion: string, mcVersion: string) {
215+
const minecraftZip = await open(mc.getVersionJar(mcVersion), { lazyEntries: true, autoClose: false })
216+
const forgeEntries = await readAllEntries(forgeZip)
217+
const mcEntries = await readAllEntries(minecraftZip)
218+
const finalZipEntries: Record<string, [Entry, ZipFile]> = {}
219+
// forge entries overwrite mc entries
220+
for (const e of mcEntries) {
221+
if (e.fileName.startsWith('META-INF')) continue
222+
finalZipEntries[e.fileName] = [e, minecraftZip]
223+
}
224+
for (const e of forgeEntries) {
225+
if (e.fileName.startsWith('META-INF')) continue
226+
finalZipEntries[e.fileName] = [e, forgeZip]
227+
}
228+
const finalZip = new WriteableZipFile()
229+
for (const [k, [e, zip]] of Object.entries(finalZipEntries)) {
230+
finalZip.addReadStream(await openEntryReadStream(zip, e), e.fileName)
231+
}
232+
finalZip.end()
233+
const dest = mc.getLibraryByPath(`net/minecraftforge/forge/${forgeVersion}/forge-${forgeVersion}.jar`)
234+
await ensureDir(dirname(dest))
235+
await pipeline(finalZip.outputStream, createWriteStream(dest))
236+
const versionId = `${mcVersion}-forge-${forgeVersion}`
237+
await ensureDir(mc.getVersionRoot(versionId))
238+
const versionJson: VersionJson = {
239+
id: versionId,
240+
inheritsFrom: mcVersion,
241+
time: new Date().toUTCString(),
242+
type: 'release',
243+
releaseTime: new Date().toUTCString(),
244+
minimumLauncherVersion: 4,
245+
arguments: {
246+
game: [
247+
],
248+
// eslint-disable-next-line no-template-curly-in-string
249+
jvm: ['-Dminecraft.applet.TargetDirectory=${game_directory}'],
250+
},
251+
mainClass: 'net.minecraft.launchwrapper.Launch',
252+
libraries: [
253+
{ name: `net.minecraftforge:forge:${forgeVersion}` },
254+
{
255+
downloads: {
256+
artifact: {
257+
path: 'guava-12.0.1.jar',
258+
sha1: 'b8e78b9af7bf45900e14c6f958486b6ca682195f',
259+
size: -1,
260+
url: 'https://files.minecraftforge.net/maven/com/google/guava/guava/12.0.1/guava-12.0.1.jar',
261+
},
262+
},
263+
name: 'com.google.guava:guava:12.0.1',
264+
},
265+
{
266+
downloads: {
267+
artifact: {
268+
path: 'argo-2.25.jar',
269+
sha1: 'bb672829fde76cb163004752b86b0484bd0a7f4b',
270+
size: -1,
271+
url: 'https://files.minecraftforge.net/maven/net/sourceforge/argo/argo/2.25/argo-2.25.jar',
272+
},
273+
},
274+
name: 'net.sourceforge.argo:argo:2.25',
275+
},
276+
{
277+
downloads: {
278+
artifact: {
279+
path: 'asm-all-4.0.jar',
280+
sha1: '98308890597acb64047f7e896638e0d98753ae82',
281+
size: -1,
282+
url: 'https://files.multimc.org/fmllibs/asm-all-4.0.jar',
283+
},
284+
},
285+
name: 'org.ow2.asm:asm-all:4.0',
286+
},
287+
{
288+
downloads: {
289+
artifact: {
290+
path: 'bcprov-jdk15on-147.jar',
291+
sha1: 'b6f5d9926b0afbde9f4dbe3db88c5247be7794bb',
292+
size: -1,
293+
url: 'https://files.multimc.org/fmllibs/bcprov-jdk15on-147.jar',
294+
},
295+
},
296+
name: 'org.bouncycastle:bcprov-jdk15on:1.47',
297+
},
298+
],
299+
}
300+
await writeFile(mc.getVersionJson(versionId), JSON.stringify(versionJson, null, 4))
301+
return versionId
302+
}
303+
209304
async function installLegacyForgeFromZip(zip: ZipFile, entries: ForgeLegacyInstallerEntriesPattern, profile: InstallProfile, mc: MinecraftFolder, jarFilePath: string, options: InstallForgeOptions) {
210305
const versionJson = profile.versionInfo
211306
if (!versionJson) {
@@ -393,10 +488,17 @@ export function installByInstallerTask(version: RequiredVersion, minecraft: Mine
393488
return `${version.mcversion}-${version.version}`
394489
}
395490
const forgeVersion = getForgeArtifactVersion()
491+
const isLegacy = version.mcversion.startsWith('1.4.')
396492
const mc = MinecraftFolder.from(minecraft)
397-
const jarPath = await this.yield(new DownloadForgeInstallerTask(forgeVersion, version.installer, mc, options)
493+
const jarPath = await this.yield(new DownloadForgeInstallerTask(forgeVersion, version.installer, mc, options, isLegacy)
398494
.map(function () { return this.installJarPath }))
399495

496+
if (isLegacy) {
497+
const forgeZip = await open(jarPath, { lazyEntries: true, autoClose: false })
498+
const versionId = await installLegacyForgeFromUniversalZip(forgeZip, mc, forgeVersion, version.mcversion)
499+
return versionId
500+
}
501+
400502
const zip = await open(jarPath, { lazyEntries: true, autoClose: false })
401503
const entries = await walkForgeInstallerEntries(zip, forgeVersion)
402504

packages/installer/minecraft.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,9 @@ export function resolveLibraryDownloadUrls(library: ResolvedLibrary, libraryOpti
569569
return [...new Set([
570570
// user defined alternative host to download
571571
...normalizeArray(libraryHosts),
572-
...normalizeArray(libraryOptions.mavenHost).map((m) => joinUrl(m, url.pathname)),
573-
library.download.url,
574572
...normalizeArray(libraryOptions.mavenHost).map((m) => joinUrl(m, library.download.path)),
573+
library.download.url,
574+
...normalizeArray(libraryOptions.mavenHost).map((m) => joinUrl(m, url.pathname).replace('/maven/maven', '/maven')),
575575
...DEFAULT_MAVENS.map((m) => joinUrl(m, library.download.path)),
576576
])]
577577
}

packages/installer/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@xmcl/task": "workspace:^*",
2525
"@xmcl/unzip": "workspace:^*",
2626
"undici": "6.0.1",
27+
"yazl": "^2.5.1",
2728
"yauzl": "^2.10.0"
2829
},
2930
"repository": {
@@ -46,6 +47,7 @@
4647
"homepage": "https://github.com/Voxelum/minecraft-launcher-core-node#readme",
4748
"devDependencies": {
4849
"@types/node": "~18.15.11",
50+
"@types/yazl": "^2.4.5",
4951
"@types/yauzl": "^2.10.0",
5052
"@xmcl/eslint-config": "workspace:^*",
5153
"esbuild": "^0.17.16",

0 commit comments

Comments
 (0)