@@ -14,6 +14,8 @@ namespace CollapseLauncher.InstallManager.Zenless
1414{
1515 internal partial class ZenlessInstall
1616 {
17+ internal const StringSplitOptions SplitOptions = StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ;
18+
1719 // ReSharper disable once StringLiteralTypo
1820 [ UnsafeAccessor ( UnsafeAccessorKind . Field , Name = "<SophonChunksInfo>k__BackingField" ) ]
1921 private static extern ref SophonChunksInfo GetChunkAssetChunksInfo ( SophonAsset element ) ;
@@ -24,8 +26,17 @@ internal partial class ZenlessInstall
2426
2527 protected override async Task FilterSophonPatchAssetList ( List < SophonPatchAsset > itemList , CancellationToken token )
2628 {
27- const StringSplitOptions splitOptions = StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ;
29+ HashSet < int > exceptMatchFieldHashSet = await GetExceptMatchFieldHashSet ( token ) ;
30+ if ( exceptMatchFieldHashSet . Count == 0 )
31+ {
32+ return ;
33+ }
2834
35+ FilterSophonAsset ( itemList , x => x . MainAssetInfo , exceptMatchFieldHashSet , token ) ;
36+ }
37+
38+ private async Task < HashSet < int > > GetExceptMatchFieldHashSet ( CancellationToken token )
39+ {
2940 string gameExecDataName =
3041 Path . GetFileNameWithoutExtension ( GameVersionManager . GamePreset . GameExecutableName ) ?? "ZenlessZoneZero" ;
3142 string gameExecDataPath = $ "{ gameExecDataName } _Data";
@@ -34,105 +45,103 @@ protected override async Task FilterSophonPatchAssetList(List<SophonPatchAsset>
3445
3546 if ( ! File . Exists ( gameExceptMatchFieldFile ) )
3647 {
37- return ;
48+ return [ ] ;
3849 }
3950
40- string exceptMatchFieldContent = await File . ReadAllTextAsync ( gameExceptMatchFieldFile , token ) ;
41- HashSet < string > exceptMatchFieldHashSet = CreateHashSet ( ) ;
42-
43- if ( exceptMatchFieldHashSet . Count == 0 )
44- {
45- return ;
46- }
51+ string exceptMatchFieldContent = await File . ReadAllTextAsync ( gameExceptMatchFieldFile , token ) ;
52+ HashSet < int > exceptMatchFieldHashSet = CreateExceptMatchFieldHashSet < int > ( exceptMatchFieldContent ) ;
4753
48- FilterAsset ( ) ;
54+ return exceptMatchFieldHashSet ;
55+ }
4956
50- return ;
57+ // ReSharper disable once IdentifierTypo
58+ private static void FilterSophonAsset < T > ( List < T > itemList , Func < T , SophonAsset ? > assetSelector , HashSet < int > exceptMatchFieldHashSet , CancellationToken token )
59+ {
60+ const string separators = "/\\ " ;
61+ scoped Span < Range > urlPathRanges = stackalloc Range [ 32 ] ;
5162
52- void FilterAsset ( )
63+ List < T > filteredList = [ ] ;
64+ foreach ( T asset in itemList )
5365 {
54- const string separators = "/\\ " ;
55- scoped Span < Range > urlPathRanges = stackalloc Range [ 32 ] ;
66+ SophonAsset ? assetSelected = assetSelector ( asset ) ;
5667
57- HashSet < string > . AlternateLookup < ReadOnlySpan < char > > alternateLookup =
58- exceptMatchFieldHashSet . GetAlternateLookup < ReadOnlySpan < char > > ( ) ;
68+ token . ThrowIfCancellationRequested ( ) ;
69+ ref SophonChunksInfo chunkInfo = ref assetSelected == null
70+ ? ref Unsafe . NullRef < SophonChunksInfo > ( )
71+ : ref GetChunkAssetChunksInfo ( assetSelected ) ;
5972
60- List < SophonPatchAsset > filteredList = [ ] ;
61- foreach ( SophonPatchAsset asset in itemList )
73+ if ( assetSelected != null && Unsafe . IsNullRef ( ref chunkInfo ) )
6274 {
63- token . ThrowIfCancellationRequested ( ) ;
64- ref SophonChunksInfo chunkInfo = ref asset . MainAssetInfo == null
65- ? ref Unsafe . NullRef < SophonChunksInfo > ( )
66- : ref GetChunkAssetChunksInfo ( asset . MainAssetInfo ) ;
67-
68- if ( asset . MainAssetInfo != null && Unsafe . IsNullRef ( ref chunkInfo ) )
69- {
70- chunkInfo = ref GetChunkAssetChunksInfoAlt ( asset . MainAssetInfo ) ;
71- }
72-
73- if ( Unsafe . IsNullRef ( ref chunkInfo ) )
74- {
75- filteredList . Add ( asset ) ;
76- continue ;
77- }
78-
79- ReadOnlySpan < char > manifestUrl = chunkInfo . ChunksBaseUrl ;
80- int rangeLen = manifestUrl . SplitAny ( urlPathRanges , separators , splitOptions ) ;
81-
82- if ( rangeLen <= 0 )
83- {
84- continue ;
85- }
86-
87- ReadOnlySpan < char > manifestStr = manifestUrl [ urlPathRanges [ rangeLen - 1 ] ] ;
88- if ( alternateLookup . Contains ( manifestStr ) )
89- {
90- continue ;
91- }
75+ chunkInfo = ref GetChunkAssetChunksInfoAlt ( assetSelected ) ;
76+ }
9277
78+ if ( Unsafe . IsNullRef ( ref chunkInfo ) )
79+ {
9380 filteredList . Add ( asset ) ;
81+ continue ;
9482 }
9583
96- if ( filteredList . Count == 0 )
84+ ReadOnlySpan < char > manifestUrl = chunkInfo . ChunksBaseUrl ;
85+ int rangeLen = manifestUrl . SplitAny ( urlPathRanges , separators , SplitOptions ) ;
86+
87+ if ( rangeLen <= 0 )
9788 {
98- return ;
89+ continue ;
9990 }
10091
101- itemList . Clear ( ) ;
102- itemList . AddRange ( filteredList ) ;
92+ ReadOnlySpan < char > manifestStr = manifestUrl [ urlPathRanges [ rangeLen - 1 ] ] ;
93+ if ( int . TryParse ( manifestStr , null , out int lookupNumber ) &&
94+ exceptMatchFieldHashSet . Contains ( lookupNumber ) )
95+ {
96+ continue ;
97+ }
98+
99+ filteredList . Add ( asset ) ;
103100 }
104101
105- HashSet < string > CreateHashSet ( )
102+ if ( filteredList . Count == 0 )
106103 {
107- const string lineFeedSeparators = "\r \n " ;
108- HashSet < string > hashSetReturn = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
109- scoped Span < Range > contentLineRange = stackalloc Range [ 2 ] ;
104+ return ;
105+ }
110106
111- ReadOnlySpan < char > contentSpan = exceptMatchFieldContent . AsSpan ( ) ;
112- int contentLineLen = contentSpan . SplitAny ( contentLineRange , lineFeedSeparators , splitOptions ) ;
107+ itemList . Clear ( ) ;
108+ itemList . AddRange ( filteredList ) ;
109+ }
113110
114- if ( contentLineLen == 0 )
115- {
116- return hashSetReturn ;
117- }
111+ internal static HashSet < T > CreateExceptMatchFieldHashSet < T > ( string exceptMatchFieldContent )
112+ where T : ISpanParsable < T >
113+ {
114+ const string lineFeedSeparators = "\r \n " ;
115+ HashSet < T > hashSetReturn = [ ] ;
116+ scoped Span < Range > contentLineRange = stackalloc Range [ 2 ] ;
118117
119- contentSpan = contentSpan [ contentLineRange [ 0 ] ] ;
120- const string separatorsChars = "|;,$#@+ " ;
121- SearchValues < char > separators = SearchValues . Create ( separatorsChars ) ;
118+ ReadOnlySpan < char > contentSpan = exceptMatchFieldContent . AsSpan ( ) ;
119+ int contentLineLen = contentSpan . SplitAny ( contentLineRange , lineFeedSeparators , SplitOptions ) ;
122120
123- foreach ( Range contentMatchRange in contentSpan . SplitAny ( separators ) )
124- {
125- if ( contentMatchRange . End . Value - contentMatchRange . Start . Value <= 0 )
126- {
127- continue ;
128- }
121+ if ( contentLineLen == 0 )
122+ {
123+ return hashSetReturn ;
124+ }
125+
126+ contentSpan = contentSpan [ contentLineRange [ 0 ] ] ;
127+ const string separatorsChars = "|;,$#@+ " ;
128+ SearchValues < char > separators = SearchValues . Create ( separatorsChars ) ;
129129
130- ReadOnlySpan < char > contentMatch = contentSpan [ contentMatchRange ] . Trim ( separatorsChars ) ;
131- hashSetReturn . Add ( contentMatch . ToString ( ) ) ;
130+ foreach ( Range contentMatchRange in contentSpan . SplitAny ( separators ) )
131+ {
132+ if ( contentMatchRange . End . Value - contentMatchRange . Start . Value <= 0 )
133+ {
134+ continue ;
132135 }
133136
134- return hashSetReturn ;
137+ ReadOnlySpan < char > contentMatch = contentSpan [ contentMatchRange ] . Trim ( separatorsChars ) ;
138+ if ( T . TryParse ( contentMatch , null , out T ? result ) )
139+ {
140+ hashSetReturn . Add ( result ) ;
141+ }
135142 }
143+
144+ return hashSetReturn ;
136145 }
137146 }
138147}
0 commit comments