55using CollapseLauncher . Interfaces ;
66using CollapseLauncher . Statics ;
77using Hi3Helper ;
8+ using Hi3Helper . Data ;
89using Hi3Helper . EncTool . Parser . AssetIndex ;
910using Hi3Helper . Http ;
1011using Hi3Helper . Sophon ;
@@ -24,108 +25,85 @@ namespace CollapseLauncher.InstallManager.Genshin;
2425#nullable enable
2526internal sealed partial class GenshinInstall
2627{
27- protected override async Task < string > DownloadPkgVersion ( DownloadClient downloadClient ,
28+ private readonly List < PkgVersionProperties > _repairAssetIndex = [ ] ;
29+ private readonly Dictionary < string , PkgVersionProperties > _repairAssetIndexDict = [ ] ;
30+
31+ protected override async Task < string > DownloadPkgVersion ( DownloadClient downloadClient ,
2832 RegionResourceVersion ? _ )
2933 {
30- // First, build the fake pkg_version from Sophon
31- string pkgVersionPath = await DownloadPkgVersionStatic ( downloadClient . GetHttpClient ( ) ,
32- GameVersionManager ,
33- GamePath ,
34- _gameAudioLangListPathStatic ,
35- token : Token . Token ) ;
36-
37- // Second, build persistent manifest from game_res dispatcher.
34+ string pkgVersionPath = Path . Combine ( GamePath , "pkg_version" ) ;
35+
36+ // Build asset index by borrowing methods from GenshinRepair instance
3837 // If game repair is not available, then skip.
3938 GamePresetProperty presetProperty = GamePropertyVault . GetCurrentGameProperty ( ) ;
4039 if ( presetProperty . GameRepair is not GenshinRepair genshinRepairInstance )
4140 {
4241 return pkgVersionPath ;
4342 }
4443
44+ // Clear last asset index list
45+ _repairAssetIndex . Clear ( ) ;
46+ _repairAssetIndexDict . Clear ( ) ;
47+
48+ // Initialize asset index and load it from GenshinRepair instance
49+ await genshinRepairInstance . BuildPrimaryManifest ( downloadClient ,
50+ _repairAssetIndex ,
51+ _repairAssetIndexDict ,
52+ CancellationToken . None ) ;
53+
4554 // Call and borrow persistent manifest method from GenshinRepair instance
4655 await genshinRepairInstance . BuildPersistentManifest ( downloadClient ,
47- null ,
48- [ ] ,
49- [ ] ,
50- Token . Token ) ;
56+ null ! ,
57+ _repairAssetIndex ,
58+ _repairAssetIndexDict ,
59+ CancellationToken . None ) ;
5160
5261 return pkgVersionPath ;
5362 }
5463
55- protected override async ValueTask ParsePkgVersions2FileInfo ( List < LocalFileInfo > pkgFileInfo ,
56- HashSet < string > pkgFileInfoHashSet ,
57- CancellationToken token )
64+ protected override ValueTask ParsePkgVersions2FileInfo ( List < LocalFileInfo > pkgFileInfo ,
65+ HashSet < string > pkgFileInfoHashSet ,
66+ CancellationToken token )
5867 {
59- // Parse primary pkg_version as main manifest
60- await base . ParsePkgVersions2FileInfo ( pkgFileInfo ,
61- pkgFileInfoHashSet ,
62- token ) ;
63-
64- string ? execPrefix = Path . GetFileNameWithoutExtension ( GameVersionManager . GamePreset . GameExecutableName ) ;
65- if ( string . IsNullOrEmpty ( execPrefix ) )
68+ foreach ( PkgVersionProperties asset in _repairAssetIndex )
6669 {
67- return ;
68- }
70+ string relativePath = asset . remoteName ;
71+ ConverterTool . NormalizePathInplaceNoTrim ( relativePath ) ;
6972
70- string basePersistentPath = $ "{ execPrefix } _Data\\ Persistent";
71- string baseStreamingAssetsPath = $ "{ execPrefix } _Data\\ StreamingAssets";
72- string persistentFolder = Path . Combine ( GamePath , basePersistentPath ) ;
73+ if ( ! pkgFileInfoHashSet . Add ( relativePath ) )
74+ {
75+ continue ;
76+ }
77+
78+ LocalFileInfo assetLocalInfo = new LocalFileInfo
79+ {
80+ FileName = Path . GetFileName ( asset . remoteName ) ,
81+ RelativePath = relativePath ,
82+ FileSize = asset . fileSize ,
83+ FullPath = Path . Combine ( GamePath , asset . remoteName )
84+ } ;
85+ assetLocalInfo . IsFileExist = File . Exists ( assetLocalInfo . FullPath ) ;
7386
74- List < string > ? audioLangList = ( GameVersionManager as GameTypeGenshinVersion ) ? . AudioVoiceLanguageList ;
75- string audioLangListPath = Path . Combine ( GamePath , basePersistentPath , "audio_lang_14" ) ;
87+ pkgFileInfo . Add ( assetLocalInfo ) ;
88+ }
7689
77- // Then add additional parsing to persistent manifests (provided by dispatcher)
78- string persistentResVersions = Path . Combine ( persistentFolder , "res_versions_persist" ) ;
79- if ( File . Exists ( persistentResVersions ) )
90+ string ? execPrefix = Path . GetFileNameWithoutExtension ( GameVersionManager . GamePreset . GameExecutableName ) ;
91+ if ( string . IsNullOrEmpty ( execPrefix ) )
8092 {
81- await ParsePersistentManifest2FileInfo ( GamePath ,
82- asset => Path . Combine ( baseStreamingAssetsPath ,
83- GenshinRepair . GetParentFromAssetRelativePath ( asset . RelativePath ,
84- out _ ) ) ,
85- persistentResVersions ,
86- pkgFileInfo ,
87- pkgFileInfoHashSet ,
88- token ) ;
93+ return ValueTask . CompletedTask ;
8994 }
9095
96+ string basePersistentPath = $ "{ execPrefix } _Data\\ Persistent";
97+ List < string > ? audioLangList = ( GameVersionManager as GameTypeGenshinVersion ) ? . AudioVoiceLanguageList ;
98+ string audioLangListPath = Path . Combine ( GamePath , basePersistentPath , "audio_lang_14" ) ;
99+
91100 // Filter unnecessary files
92101 if ( audioLangList != null )
93102 {
94103 GenshinRepair . EliminateUnnecessaryAssetIndex ( audioLangListPath , audioLangList , pkgFileInfo , '\\ ' , x => x . FullPath ) ;
95104 }
96- }
97-
98- private static async Task ParsePersistentManifest2FileInfo ( string baseGamePath ,
99- Func < LocalFileInfo , string ? > ? assetGetMiddlePath ,
100- string pkgFilePath ,
101- List < LocalFileInfo > pkgFileInfo ,
102- HashSet < string > pkgFileInfoHashSet ,
103- CancellationToken token )
104- {
105- using StreamReader reader = File . OpenText ( pkgFilePath ) ;
106- while ( await reader . ReadLineAsync ( token ) is { } line )
107- {
108- LocalFileInfo ? localFileInfo = line . Deserialize ( LocalFileInfoJsonContext . Default . LocalFileInfo ) ;
109105
110- // If null, then go to next line
111- if ( localFileInfo == null )
112- continue ;
113-
114- string ? middlePath = assetGetMiddlePath ? . Invoke ( localFileInfo ) ;
115- string fullBasePath = string . IsNullOrEmpty ( middlePath ) ? baseGamePath : Path . Combine ( baseGamePath , middlePath ) ;
116-
117- localFileInfo . FullPath = Path . Combine ( fullBasePath , localFileInfo . RelativePath ) ;
118- localFileInfo . FileName = Path . GetFileName ( localFileInfo . RelativePath ) ;
119- localFileInfo . IsFileExist = File . Exists ( localFileInfo . FullPath ) ;
120-
121- string relativePathNoBase = Path . Combine ( middlePath ?? "" , localFileInfo . RelativePath ) ;
122-
123- // Add it to the list and hashset (if it's not registered yet)
124- if ( pkgFileInfoHashSet . Add ( relativePathNoBase ) )
125- {
126- pkgFileInfo . Add ( localFileInfo ) ;
127- }
128- }
106+ return ValueTask . CompletedTask ;
129107 }
130108
131109 public static async Task < string > DownloadPkgVersionStatic ( HttpClient client ,
0 commit comments