1
1
use std:: {
2
2
collections:: HashMap ,
3
3
fmt:: Debug ,
4
+ fs:: File ,
4
5
io:: Read ,
5
6
marker:: PhantomData ,
6
7
path:: { Path , PathBuf } ,
@@ -10,7 +11,8 @@ use std::{
10
11
use anyhow:: { anyhow, bail} ;
11
12
use itertools:: Itertools ;
12
13
use serde:: { Deserialize , Serialize } ;
13
- use tracing:: { error, warn} ;
14
+ use tokio:: io:: AsyncWriteExt ;
15
+ use tracing:: { error, info, warn} ;
14
16
15
17
use crate :: {
16
18
configs:: profile:: Loader ,
@@ -24,7 +26,7 @@ use crate::{
24
26
instance:: profile:: LoaderProfile ,
25
27
loaders:: vanilla:: VanillaLibrariesMapper ,
26
28
markers:: Undefined ,
27
- maven_data:: MavenData ,
29
+ maven_data:: { MavenArtifact , MavenData } ,
28
30
repository:: {
29
31
manifest:: { Argument , Arguments , Library } ,
30
32
simple_args:: SimpleArgs ,
@@ -34,12 +36,8 @@ use crate::{
34
36
} ;
35
37
36
38
const FORGE_REPO_URL : & str = "https://maven.minecraftforge.net" ;
37
- const FORGE_GROUP : & str = "net.minecraftforge" ;
38
- const FORGE_ARTIFACT : & str = "forge" ;
39
39
40
40
const NEO_FORGE_REPO_URL : & str = "https://maven.neoforged.net/releases/" ;
41
- const NEO_FORGE_GROUP : & str = "net.neoforged" ;
42
- const NEO_FORGE_ARTIFACT : & str = "neoforge" ;
43
41
44
42
/// Some versions require to have a suffix
45
43
const FORGE_SUFFIXES : & [ ( & str , & [ & str ] ) ] = & [
@@ -61,6 +59,7 @@ pub struct Forge {
61
59
downloader : LibrariesDownloader ,
62
60
game_version : String ,
63
61
forge_version : String ,
62
+ libraries_dir : PathBuf ,
64
63
}
65
64
66
65
impl Forge {
@@ -221,15 +220,14 @@ impl Forge {
221
220
222
221
impl LibrariesMapper < ForgeOldLibrary > for ForgeOldLibrariesMapper < ' _ > {
223
222
fn proceed ( & self , library : & ForgeOldLibrary ) -> Option < FileDownloader > {
224
- let ( name, url, is_required) = ( library. name . as_str ( ) , library. url . as_deref ( ) , library. clientreq ) ;
225
-
226
- is_required
227
- . filter ( |x| * x)
228
- . map ( |_| name)
229
- . map ( MavenData :: new)
230
- . map ( |m| ( m. url , m. path ) )
231
- . and_then ( |( url_part, path) | url. map ( |u| format ! ( "{u}{url_part}" ) ) . map ( |url| ( url, path) ) )
232
- . map ( |( url, path) | FileDownloader :: new ( url, self . path . join ( path) ) )
223
+ let ( name, url) = ( library. name . as_str ( ) , library. url . as_deref ( ) ) ;
224
+
225
+ let maven_data = MavenData :: new ( name) ;
226
+ let url = url. map_or ( format ! ( "https://libraries.minecraft.net/{}" , maven_data. url) , |url| {
227
+ format ! ( "{url}{}" , & maven_data. url)
228
+ } ) ;
229
+
230
+ Some ( FileDownloader :: new ( url, self . path . join ( & maven_data. path ) ) )
233
231
}
234
232
}
235
233
@@ -243,6 +241,7 @@ impl Forge {
243
241
downloader,
244
242
game_version,
245
243
forge_version,
244
+ libraries_dir : game_paths. libraries . clone ( ) ,
246
245
} )
247
246
}
248
247
}
@@ -264,7 +263,48 @@ impl Downloader for Forge {
264
263
}
265
264
266
265
fn io ( & self ) -> PinnedFutureWithBounds < anyhow:: Result < ( ) > > {
267
- Box :: pin ( async { Ok ( ( ) ) } )
266
+ struct ForgeLibraryExtractionData {
267
+ library_path : String ,
268
+ target_path : PathBuf ,
269
+ }
270
+
271
+ async fn inner ( installer_path : PathBuf , libraries_dir : PathBuf , lib_data : Option < ForgeLibraryExtractionData > ) -> anyhow:: Result < ( ) > {
272
+ info ! ( "Applying Forge IO" ) ;
273
+ if let Some ( data) = lib_data {
274
+ info ! ( "Extracting {}" , & data. library_path) ;
275
+ let file = tokio:: fs:: File :: open ( installer_path) . await ?;
276
+ let mut archive = zip:: ZipArchive :: new ( file. into_std ( ) . await ) ?;
277
+ let mut library_bytes = Vec :: new ( ) ;
278
+
279
+ // If it's not in it's own scope then the future cannot be send between thread safely
280
+ {
281
+ let mut library = archive. by_name ( & data. library_path ) ?;
282
+ library. read_to_end ( & mut library_bytes) ?;
283
+ }
284
+
285
+ let target_path = libraries_dir. join ( data. target_path ) ;
286
+
287
+ if let Some ( parent) = target_path. parent ( ) . filter ( |p| !p. exists ( ) ) {
288
+ tokio:: fs:: create_dir_all ( parent) . await ?;
289
+ }
290
+
291
+ let mut target = tokio:: fs:: File :: create ( target_path) . await ?;
292
+ target. write_all ( library_bytes. as_slice ( ) ) . await ?;
293
+ }
294
+
295
+ Ok ( ( ) )
296
+ }
297
+
298
+ let extraction = match & self . profile {
299
+ ForgeProfile :: Old ( old) => Some ( ForgeLibraryExtractionData {
300
+ library_path : old. install . file_path . clone ( ) ,
301
+ target_path : MavenData :: new ( & old. install . path ) . path ,
302
+ } ) ,
303
+ ForgeProfile :: New ( _) => None ,
304
+ } ;
305
+
306
+ let ( installer_path, libraries_dir) = ( self . installer_path ( ) , self . libraries_dir . clone ( ) ) ;
307
+ Box :: pin ( inner ( installer_path, libraries_dir, extraction) )
268
308
}
269
309
}
270
310
@@ -324,7 +364,7 @@ impl ForgeProfile {
324
364
args. iter ( )
325
365
. filter_map ( |a| match a {
326
366
Argument :: String ( s) => Some ( s) ,
327
- _ => None ,
367
+ Argument :: Struct { .. } => None ,
328
368
} )
329
369
. cloned ( )
330
370
. collect_vec ( )
@@ -341,7 +381,7 @@ impl ForgeProfile {
341
381
warn ! ( "Cannot find `--tweakClass` parameter in the Forge arguments list. Game might not launch." ) ;
342
382
Vec :: new ( )
343
383
} ,
344
- |( _, val) | vec ! [ "--tweakClass" , val] . into_iter ( ) . map ( String :: from) . collect_vec ( ) ,
384
+ |( _, val) | vec ! [ "--tweakClass" , val. trim ( ) ] . into_iter ( ) . map ( String :: from) . collect_vec ( ) ,
345
385
) ,
346
386
jvm : Vec :: new ( ) ,
347
387
} ,
@@ -354,25 +394,23 @@ impl ForgeProfile {
354
394
. libraries
355
395
. iter ( )
356
396
. map ( |lib| SimpleLib {
357
- jar : lib
358
- . downloads
359
- . artifact
360
- . as_ref ( )
361
- . and_then ( |a| a. path . as_ref ( ) )
362
- . map ( PathBuf :: from)
363
- . unwrap_or_else ( || {
397
+ jar : lib. downloads . artifact . as_ref ( ) . and_then ( |a| a. path . as_ref ( ) ) . map_or_else (
398
+ || {
364
399
warn ! ( "Forge library does not have path. Game might not launch." ) ;
365
400
PathBuf :: new ( )
366
- } ) ,
401
+ } ,
402
+ PathBuf :: from,
403
+ ) ,
404
+ artifact : MavenArtifact :: new ( & lib. name ) ,
367
405
} )
368
406
. collect_vec ( ) ,
369
407
ForgeProfile :: Old ( old) => old
370
408
. version_info
371
409
. libraries
372
410
. iter ( )
373
- . filter ( |lib| lib. clientreq . is_some_and ( |required| required) )
411
+ // .filter(|lib| lib.clientreq.is_some_and(|required| required))
374
412
. map ( |lib| lib. name . as_str ( ) )
375
- . map ( MavenData :: new)
413
+ . map ( MavenArtifact :: new)
376
414
. map ( SimpleLib :: from)
377
415
. collect_vec ( ) ,
378
416
}
@@ -402,23 +440,23 @@ pub struct Logging {}
402
440
#[ derive( Serialize , Deserialize , Debug ) ]
403
441
#[ serde( rename_all = "camelCase" ) ]
404
442
pub struct ForgeProfileOld {
405
- // pub install: Install,
443
+ pub install : Install ,
406
444
pub version_info : VersionInfo ,
407
445
}
408
446
409
- // #[derive(Serialize, Deserialize, Debug)]
410
- // #[serde(rename_all = "camelCase")]
411
- // pub struct Install {
412
- // pub profile_name: String,
413
- // pub target: String,
414
- // pub path: String,
415
- // pub version: String,
416
- // pub file_path: String,
417
- // pub welcome: String,
418
- // pub minecraft: String,
419
- // pub mirror_list: String,
420
- // pub logo: String,
421
- // }
447
+ #[ derive( Serialize , Deserialize , Debug ) ]
448
+ #[ serde( rename_all = "camelCase" ) ]
449
+ pub struct Install {
450
+ // pub profile_name: String,
451
+ // pub target: String,
452
+ pub path : String ,
453
+ // pub version: String,
454
+ pub file_path : String ,
455
+ // pub welcome: String,
456
+ // pub minecraft: String,
457
+ // pub mirror_list: String,
458
+ // pub logo: String,
459
+ }
422
460
423
461
#[ derive( Serialize , Deserialize , Debug ) ]
424
462
#[ serde( rename_all = "camelCase" ) ]
0 commit comments