1
1
import { LibraryInfo , MinecraftFolder , MinecraftLocation , Version as VersionJson } from '@xmcl/core'
2
2
import { parse as parseForge } from '@xmcl/forge-site-parser'
3
3
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'
5
5
import { createWriteStream } from 'fs'
6
6
import { writeFile } from 'fs/promises'
7
7
import { dirname , join } from 'path'
8
8
import { pipeline } from 'stream/promises'
9
9
import { Dispatcher , request } from 'undici'
10
10
import { Entry , ZipFile } from 'yauzl'
11
+ import { ZipFile as WriteableZipFile } from 'yazl'
11
12
import { DownloadTask } from './downloadTask'
12
13
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'
15
16
import { ZipValidator } from './zipValdiator'
16
17
17
18
export interface ForgeVersionList {
@@ -144,8 +145,12 @@ export interface InstallForgeOptions extends LibraryOptions, InstallOptionsBase,
144
145
export class DownloadForgeInstallerTask extends DownloadTask {
145
146
readonly installJarPath : string
146
147
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 } `
149
154
let url : string
150
155
if ( installer ) {
151
156
try {
@@ -161,11 +166,11 @@ export class DownloadForgeInstallerTask extends DownloadTask {
161
166
}
162
167
163
168
const library = VersionJson . resolveLibrary ( {
164
- name : `net.minecraftforge:forge:${ forgeVersion } :installer ` ,
169
+ name : `net.minecraftforge:forge:${ forgeVersion } :${ classifier } ` ,
165
170
downloads : {
166
171
artifact : {
167
172
url,
168
- path : `net/minecraftforge/forge/${ forgeVersion } /forge-${ forgeVersion } -installer.jar ` ,
173
+ path : `net/minecraftforge/forge/${ forgeVersion } /forge-${ forgeVersion } -${ classifier } . ${ ext } ` ,
169
174
size : - 1 ,
170
175
sha1 : installer ?. sha1 || '' ,
171
176
} ,
@@ -206,6 +211,96 @@ function extractEntryTo(zip: ZipFile, e: Entry, dest: string) {
206
211
return openEntryReadStream ( zip , e ) . then ( ( stream ) => pipeline ( stream , createWriteStream ( dest ) ) )
207
212
}
208
213
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
+
209
304
async function installLegacyForgeFromZip ( zip : ZipFile , entries : ForgeLegacyInstallerEntriesPattern , profile : InstallProfile , mc : MinecraftFolder , jarFilePath : string , options : InstallForgeOptions ) {
210
305
const versionJson = profile . versionInfo
211
306
if ( ! versionJson ) {
@@ -393,10 +488,17 @@ export function installByInstallerTask(version: RequiredVersion, minecraft: Mine
393
488
return `${ version . mcversion } -${ version . version } `
394
489
}
395
490
const forgeVersion = getForgeArtifactVersion ( )
491
+ const isLegacy = version . mcversion . startsWith ( '1.4.' )
396
492
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 )
398
494
. map ( function ( ) { return this . installJarPath } ) )
399
495
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
+
400
502
const zip = await open ( jarPath , { lazyEntries : true , autoClose : false } )
401
503
const entries = await walkForgeInstallerEntries ( zip , forgeVersion )
402
504
0 commit comments