Skip to content

Commit a580f3c

Browse files
committed
[ZZZ] Add ability on Game Repair/Cache Update to skip excluded assets
+ Applied for both Sophon Chunk and Sophon Patch-based update
1 parent 17bc493 commit a580f3c

File tree

8 files changed

+205
-109
lines changed

8 files changed

+205
-109
lines changed

CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.Sophon.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,9 @@ await TryGetAdditionalPackageForSophonDiff(httpClient,
792792
downloadSpeedLimiter);
793793
}
794794

795+
// Filter asset list
796+
await FilterSophonPatchAssetList(sophonUpdateAssetList, Token.Token);
797+
795798
// Get the remote chunk size
796799
ProgressPerFileSizeTotal = sophonUpdateAssetList.GetCalculatedDiffSize(!isPreloadMode);
797800
ProgressPerFileSizeCurrent = 0;
@@ -927,6 +930,12 @@ await Parallel.ForEachAsync(sophonUpdateAssetList.Where(x => !x.IsDirectory),
927930
}
928931
}
929932

933+
protected virtual Task FilterSophonPatchAssetList(List<SophonAsset> itemList, CancellationToken token)
934+
{
935+
// NOP
936+
return Task.CompletedTask;
937+
}
938+
930939
private ValueTask RunSophonAssetDownloadThread(HttpClient client,
931940
SophonAsset asset,
932941
ParallelOptions parallelOptions)

CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.SophonPatch.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ await GetAlterSophonPatchAssets(httpClient,
117117
downloadSpeedLimiter,
118118
Token.Token);
119119

120-
// Filter asset list based on
120+
// Filter asset list
121121
await FilterSophonPatchAssetList(patchAssets.AssetList, Token.Token);
122122

123123
// Start the patch pipeline
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Hi3Helper.Sophon;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
// ReSharper disable CheckNamespace
6+
7+
#nullable enable
8+
namespace CollapseLauncher.InstallManager.Zenless
9+
{
10+
internal partial class ZenlessInstall
11+
{
12+
protected override async Task FilterSophonPatchAssetList(List<SophonAsset> itemList, CancellationToken token)
13+
{
14+
HashSet<int> exceptMatchFieldHashSet = await GetExceptMatchFieldHashSet(token);
15+
if (exceptMatchFieldHashSet.Count == 0)
16+
{
17+
return;
18+
}
19+
20+
FilterSophonAsset(itemList, x => x, exceptMatchFieldHashSet, token);
21+
}
22+
}
23+
}

CollapseLauncher/Classes/InstallManagement/Zenless/ZenlessInstall.SophonPatch.cs

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

CollapseLauncher/Classes/RepairManagement/Zenless/ZenlessRepair.Extensions.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ internal static async IAsyncEnumerable<PkgVersionProperties> RegisterSleepyFileI
8484
isForceStoreInPersistent = manifest.IsPersistentFile,
8585
isPatch = manifest.IsPersistentFile,
8686
md5 = Convert.ToHexStringLower(manifest.Xxh64Hash),
87-
remoteName = manifest.FileRelativePath
87+
remoteName = manifest.FileRelativePath,
88+
associatedObject = manifest
8889
};
8990
}
9091
}
@@ -143,6 +144,7 @@ internal static async IAsyncEnumerable<PkgVersionProperties> RegisterSleepyFileI
143144
asset.fileSize,
144145
asset.md5,
145146
FileType.Generic,
147+
asset.associatedObject,
146148
asset.isPatch);
147149

148150
ReadOnlySpan<char> relTypeRelativePath = asRemoteProperty.GetAssetRelativePath(out RepairAssetType assetType);
@@ -189,6 +191,7 @@ private static FilePropertiesRemote GetNormalizedFilePropertyTypeBased(string re
189191
long fileSize,
190192
string hash,
191193
FileType type = FileType.Generic,
194+
object associatedObject = null!,
192195
bool isPatchApplicable = false)
193196
{
194197
string remoteAbsolutePath = type switch
@@ -205,7 +208,8 @@ private static FilePropertiesRemote GetNormalizedFilePropertyTypeBased(string re
205208
S = fileSize,
206209
N = localAbsolutePath,
207210
RN = remoteAbsolutePath,
208-
IsPatchApplicable = isPatchApplicable
211+
IsPatchApplicable = isPatchApplicable,
212+
AssociatedObject = associatedObject
209213
};
210214
}
211215

0 commit comments

Comments
 (0)